From ec4d342aa9b536c71bcf0d75249549860941793b Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Mon, 14 Mar 2011 12:07:26 +0100 Subject: [PATCH] Support per surface frame events This fixes tearing with multi head. --- clients/gears.c | 4 +- clients/resizor.c | 7 ++-- clients/simple-client.c | 9 ++-- clients/smoke.c | 4 +- clients/window.c | 6 +++ clients/window.h | 3 ++ compositor/compositor-drm.c | 39 ++++++++--------- compositor/compositor-wayland.c | 30 +++++++------- compositor/compositor-x11.c | 22 +++++----- compositor/compositor.c | 92 ++++++++++++++++++++++++++++++++++------- compositor/compositor.h | 11 +++-- compositor/shell.c | 1 + 12 files changed, 155 insertions(+), 73 deletions(-) diff --git a/clients/gears.c b/clients/gears.c index 8496abb..5c2b3cf 100644 --- a/clients/gears.c +++ b/clients/gears.c @@ -334,7 +334,7 @@ redraw_handler(struct window *window, void *data) } static void -frame_callback(void *data, uint32_t time) +frame_callback(struct wl_surface *surface, void *data, uint32_t time) { struct gears *gears = data; @@ -344,6 +344,7 @@ frame_callback(void *data, uint32_t time) window_schedule_redraw(gears->window); wl_display_frame_callback(display_get_display(gears->d), + window_get_wl_surface(gears->window), frame_callback, gears); } @@ -412,6 +413,7 @@ gears_create(struct display *display) draw_gears(gears); wl_display_frame_callback(display_get_display(gears->d), + window_get_wl_surface(gears->window), frame_callback, gears); return gears; diff --git a/clients/resizor.c b/clients/resizor.c index 0ac02f6..fc5dedd 100644 --- a/clients/resizor.c +++ b/clients/resizor.c @@ -49,7 +49,7 @@ struct resizor { }; static void -frame_callback(void *data, uint32_t time) +frame_callback(struct wl_surface *surface, void *data, uint32_t time) { struct resizor *resizor = data; double force, height; @@ -107,6 +107,7 @@ resizor_draw(struct resizor *resizor) if (fabs(resizor->height.previous - resizor->height.target) > 0.1) { wl_display_frame_callback(display_get_display(resizor->display), + window_get_wl_surface(resizor->window), frame_callback, resizor); } } @@ -140,11 +141,11 @@ key_handler(struct window *window, struct input *input, uint32_t time, switch (sym) { case XK_Down: resizor->height.target = 400; - frame_callback(resizor, 0); + frame_callback(window_get_wl_surface(window), resizor, 0); break; case XK_Up: resizor->height.target = 200; - frame_callback(resizor, 0); + frame_callback(window_get_wl_surface(window), resizor, 0); break; } } diff --git a/clients/simple-client.c b/clients/simple-client.c index 89718df..01afaae 100644 --- a/clients/simple-client.c +++ b/clients/simple-client.c @@ -216,7 +216,7 @@ create_surface(struct window *window) } static void -redraw(void *data, uint32_t time) +redraw(struct wl_surface *surface, void *data, uint32_t time) { struct window *window = data; static const GLfloat verts[3][2] = { @@ -267,7 +267,9 @@ redraw(void *data, uint32_t time) glFlush(); eglSwapBuffers(window->display->egl.dpy, window->egl_surface); - wl_display_frame_callback(window->display->display, redraw, window); + wl_display_frame_callback(window->display->display, + window->surface, + redraw, window); } static void @@ -315,7 +317,8 @@ main(int argc, char **argv) create_surface(&window); init_gl(&window); - wl_display_frame_callback(display.display, redraw, &window); + wl_display_frame_callback(display.display, window.surface, + redraw, &window); wl_display_get_fd(display.display, event_mask_update, &display); while (true) diff --git a/clients/smoke.c b/clients/smoke.c index 0710b3a..32ca0c0 100644 --- a/clients/smoke.c +++ b/clients/smoke.c @@ -173,7 +173,7 @@ static void render(struct smoke *smoke) } static void -frame_callback(void *data, uint32_t time) +frame_callback(struct wl_surface *surface, void *data, uint32_t time) { struct smoke *smoke = data; @@ -201,6 +201,7 @@ frame_callback(void *data, uint32_t time) window_damage(smoke->window, 0, 0, smoke->width, smoke->height); wl_display_frame_callback(display_get_display(smoke->display), + window_get_wl_surface(smoke->window), frame_callback, smoke); } @@ -288,6 +289,7 @@ int main(int argc, char *argv[]) window_set_user_data(smoke.window, &smoke); wl_display_frame_callback(display_get_display(d), + window_get_wl_surface(smoke.window), frame_callback, &smoke); display_run(d); diff --git a/clients/window.c b/clients/window.c index 0c93b9c..ec1714e 100644 --- a/clients/window.c +++ b/clients/window.c @@ -792,6 +792,12 @@ window_get_surface(struct window *window) return cairo_surface_reference(window->cairo_surface); } +struct wl_surface * +window_get_wl_surface(struct window *window) +{ + return window->surface; +} + static int get_pointer_location(struct window *window, int32_t x, int32_t y) { diff --git a/clients/window.h b/clients/window.h index 7073f4a..c5285f7 100644 --- a/clients/window.h +++ b/clients/window.h @@ -157,6 +157,9 @@ window_damage(struct window *window, int32_t x, int32_t y, cairo_surface_t * window_get_surface(struct window *window); +struct wl_surface * +window_get_wl_surface(struct window *window); + void window_flush(struct window *window); diff --git a/compositor/compositor-drm.c b/compositor/compositor-drm.c index aa58a31..c769874 100644 --- a/compositor/compositor-drm.c +++ b/compositor/compositor-drm.c @@ -79,23 +79,24 @@ drm_output_prepare_render(struct wlsc_output *output_base) return 0; } -static void -drm_compositor_present(struct wlsc_compositor *ec) +static int +drm_output_present(struct wlsc_output *output_base) { - struct drm_compositor *c = (struct drm_compositor *) ec; - struct drm_output *output; + struct drm_output *output = (struct drm_output *) output_base; + struct drm_compositor *c = + (struct drm_compositor *) output->base.compositor; - wl_list_for_each(output, &ec->output_list, base.link) { - if (drm_output_prepare_render(&output->base)) - continue; - glFlush(); + if (drm_output_prepare_render(&output->base)) + return -1; + glFlush(); + + output->current ^= 1; - output->current ^= 1; + drmModePageFlip(c->drm.fd, output->crtc_id, + output->fb_id[output->current ^ 1], + DRM_MODE_PAGE_FLIP_EVENT, output); - drmModePageFlip(c->drm.fd, output->crtc_id, - output->fb_id[output->current ^ 1], - DRM_MODE_PAGE_FLIP_EVENT, output); - } + return 0; } static void @@ -103,16 +104,10 @@ page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { struct wlsc_output *output = data; - struct wlsc_compositor *compositor = output->compositor; uint32_t msecs; - /* run synchronized to first output, ignore other pflip events. - * FIXME: support per output/surface frame callbacks */ - if (output == container_of(compositor->output_list.prev, - struct wlsc_output, link)) { - msecs = sec * 1000 + usec / 1000; - wlsc_compositor_finish_frame(compositor, msecs); - } + msecs = sec * 1000 + usec / 1000; + wlsc_output_finish_frame(output, msecs); } static void @@ -287,6 +282,7 @@ create_output_for_connector(struct drm_compositor *ec, } output->base.prepare_render = drm_output_prepare_render; + output->base.present = drm_output_present; wl_list_insert(ec->base.output_list.prev, &output->base.link); @@ -523,7 +519,6 @@ drm_compositor_create(struct wl_display *display, int connector) } ec->base.destroy = drm_destroy; - ec->base.present = drm_compositor_present; ec->base.create_buffer = wlsc_shm_buffer_create; ec->base.focus = 1; diff --git a/compositor/compositor-wayland.c b/compositor/compositor-wayland.c index 524a25c..097b23e 100644 --- a/compositor/compositor-wayland.c +++ b/compositor/compositor-wayland.c @@ -156,11 +156,11 @@ wayland_compositor_init_egl(struct wayland_compositor *c) } static void -frame_callback(void *data, uint32_t time) +frame_callback(struct wl_surface *surface, void *data, uint32_t time) { - struct wayland_compositor *c = (struct wayland_compositor *) data; + struct wlsc_output *output = data; - wlsc_compositor_finish_frame(&c->base, time); + wlsc_output_finish_frame(output, time); } static int @@ -178,20 +178,22 @@ wayland_output_prepare_render(struct wlsc_output *output_base) return 0; } -static void -wayland_compositor_present(struct wlsc_compositor *base) +static int +wayland_output_present(struct wlsc_output *output_base) { - struct wayland_compositor *c = (struct wayland_compositor *) base; - struct wayland_output *output; + struct wayland_output *output = (struct wayland_output *) output_base; + struct wayland_compositor *c = + (struct wayland_compositor *) output->base.compositor; - wl_list_for_each(output, &base->output_list, base.link) { - if (wayland_output_prepare_render(&output->base)) - continue; + if (wayland_output_prepare_render(&output->base)) + return -1; - eglSwapBuffers(c->base.display, output->egl_surface); - } + eglSwapBuffers(c->base.display, output->egl_surface); + wl_display_frame_callback(c->parent.display, + output->parent.surface, + frame_callback, &output->base); - wl_display_frame_callback(c->parent.display, frame_callback, c); + return 0; } static int @@ -243,6 +245,7 @@ wayland_compositor_create_output(struct wayland_compositor *c, glClearColor(0, 0, 0, 0.5); output->base.prepare_render = wayland_output_prepare_render; + output->base.present = wayland_output_present; wl_list_insert(c->base.output_list.prev, &output->base.link); @@ -477,7 +480,6 @@ wayland_compositor_create(struct wl_display *display, int width, int height) return NULL; c->base.destroy = wayland_destroy; - c->base.present = wayland_compositor_present; c->base.create_buffer = wlsc_shm_buffer_create; /* Can't init base class until we have a current egl context */ diff --git a/compositor/compositor-x11.c b/compositor/compositor-x11.c index ba593c1..f837a6a 100644 --- a/compositor/compositor-x11.c +++ b/compositor/compositor-x11.c @@ -171,24 +171,24 @@ x11_output_prepare_render(struct wlsc_output *output_base) return 0; } -static void -x11_compositor_present(struct wlsc_compositor *base) +static int +x11_output_present(struct wlsc_output *output_base) { - struct x11_compositor *c = (struct x11_compositor *) base; - struct x11_output *output; + struct x11_output *output = (struct x11_output *) output_base; + struct wlsc_compositor *ec = output->base.compositor; struct timeval tv; uint32_t msec; - wl_list_for_each(output, &c->base.output_list, base.link) { - if (x11_output_prepare_render(&output->base)) - continue; + if (x11_output_prepare_render(&output->base)) + return -1; - eglSwapBuffers(c->base.display, output->egl_surface); - } + eglSwapBuffers(ec->display, output->egl_surface); gettimeofday(&tv, NULL); msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; - wlsc_compositor_finish_frame(&c->base, msec); + wlsc_output_finish_frame(&output->base, msec); + + return 0; } static void @@ -338,6 +338,7 @@ x11_compositor_create_output(struct x11_compositor *c, int width, int height) } output->base.prepare_render = x11_output_prepare_render; + output->base.present = x11_output_present; wl_list_insert(c->base.output_list.prev, &output->base.link); @@ -569,7 +570,6 @@ x11_compositor_create(struct wl_display *display, int width, int height) return NULL; c->base.destroy = x11_destroy; - c->base.present = x11_compositor_present; c->base.create_buffer = wlsc_shm_buffer_create; /* Can't init base class until we have a current egl context */ diff --git a/compositor/compositor.c b/compositor/compositor.c index 23465da..90fd51c 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -479,9 +479,20 @@ wlsc_surface_update_matrix(struct wlsc_surface *es) } void -wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs) +wlsc_output_finish_frame(struct wlsc_output *output, int msecs) { - wl_display_post_frame(compositor->wl_display, msecs); + struct wlsc_compositor *compositor = output->compositor; + struct wlsc_surface *es; + + wl_list_for_each(es, &compositor->surface_list, link) { + if (es->output == output) { + wl_display_post_frame(compositor->wl_display, + &es->surface, msecs); + } + } + + output->finished = 1; + wl_event_source_timer_update(compositor->timer_source, 5); compositor->repaint_on_timeout = 1; } @@ -549,24 +560,38 @@ repaint(void *data) { struct wlsc_compositor *ec = data; struct wlsc_output *output; + int repainted_all_outputs = 1; - if (!ec->repaint_needed) { - ec->repaint_on_timeout = 0; - return; - } + wl_list_for_each(output, &ec->output_list, link) { + if (!output->repaint_needed) + continue; + + if (!output->finished) { + repainted_all_outputs = 0; + continue; + } - wl_list_for_each(output, &ec->output_list, link) wlsc_output_repaint(output); + output->finished = 0; + output->present(output); - ec->present(ec); + output->repaint_needed = 0; + } - ec->repaint_needed = 0; + if (repainted_all_outputs) + ec->repaint_on_timeout = 0; + else + wl_event_source_timer_update(ec->timer_source, 1); } void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor) { - compositor->repaint_needed = 1; + struct wlsc_output *output; + + wl_list_for_each(output, &compositor->output_list, link) + output->repaint_needed = 1; + if (compositor->repaint_on_timeout) return; @@ -581,6 +606,32 @@ surface_destroy(struct wl_client *client, wl_resource_destroy(&surface->resource, client); } +void +wlsc_surface_assign_output(struct wlsc_surface *es) +{ + struct wlsc_compositor *ec = es->compositor; + struct wlsc_output *output; + + struct wlsc_output *tmp = es->output; + es->output = NULL; + + wl_list_for_each(output, &ec->output_list, link) { + if (output->x < es->x && es->x < output->x + output->width && + output->y < es->y && es->y < output->y + output->height) { + if (output != tmp) + printf("assiging surface %p to output %p\n", + es, output); + es->output = output; + } + } + + if (es->output == NULL) { + printf("no output found\n"); + es->output = container_of(ec->output_list.next, + struct wlsc_output, link); + } +} + static void surface_attach(struct wl_client *client, struct wl_surface *surface, struct wl_buffer *buffer, @@ -601,6 +652,8 @@ surface_attach(struct wl_client *client, es->y += y; es->width = buffer->width; es->height = buffer->height; + if (x != 0 || y != 0) + wlsc_surface_assign_output(es); wlsc_surface_update_matrix(es); } @@ -609,12 +662,16 @@ surface_map_toplevel(struct wl_client *client, struct wl_surface *surface) { struct wlsc_surface *es = (struct wlsc_surface *) surface; + struct wlsc_compositor *ec = es->compositor; switch (es->map_type) { case WLSC_SURFACE_MAP_UNMAPPED: es->x = 10 + random() % 400; es->y = 10 + random() % 400; wlsc_surface_update_matrix(es); + /* assign to first output */ + es->output = container_of(ec->output_list.next, + struct wlsc_output, link); wl_list_insert(&es->compositor->surface_list, &es->link); break; case WLSC_SURFACE_MAP_TOPLEVEL: @@ -644,6 +701,8 @@ surface_map_transient(struct wl_client *client, switch (es->map_type) { case WLSC_SURFACE_MAP_UNMAPPED: wl_list_insert(&es->compositor->surface_list, &es->link); + /* assign to parents output */ + es->output = pes->output; break; case WLSC_SURFACE_MAP_FULLSCREEN: es->fullscreen_output = NULL; @@ -666,10 +725,17 @@ surface_map_fullscreen(struct wl_client *client, struct wl_surface *surface) struct wlsc_surface *es = (struct wlsc_surface *) surface; struct wlsc_output *output; + /* FIXME: Fullscreen on first output */ + /* FIXME: Handle output going away */ + output = container_of(es->compositor->output_list.next, + struct wlsc_output, link); + switch (es->map_type) { case WLSC_SURFACE_MAP_UNMAPPED: es->x = 10 + random() % 400; es->y = 10 + random() % 400; + /* assign to first output */ + es->output = output; wl_list_insert(&es->compositor->surface_list, &es->link); break; case WLSC_SURFACE_MAP_FULLSCREEN: @@ -678,11 +744,6 @@ surface_map_fullscreen(struct wl_client *client, struct wl_surface *surface) break; } - /* FIXME: Fullscreen on first output */ - /* FIXME: Handle output going away */ - output = container_of(es->compositor->output_list.next, - struct wlsc_output, link); - es->saved_x = es->x; es->saved_y = es->y; es->x = (output->width - es->width) / 2; @@ -1362,6 +1423,7 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c, background_create(output, option_background); output->flags = flags; + output->finished = 1; wlsc_output_move(output, x, y); output->object.interface = &wl_output_interface; diff --git a/compositor/compositor.h b/compositor/compositor.h index 637fde0..6a392fc 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -48,8 +48,11 @@ struct wlsc_output { int32_t x, y, width, height; pixman_region32_t previous_damage_region; uint32_t flags; + int repaint_needed; + int finished; int (*prepare_render)(struct wlsc_output *output); + int (*present)(struct wlsc_output *output); }; enum wlsc_pointer_type { @@ -103,7 +106,6 @@ struct wlsc_compositor { /* Repaint state. */ struct wl_event_source *timer_source; - int repaint_needed; int repaint_on_timeout; struct timespec previous_swap; pixman_region32_t damage_region; @@ -114,7 +116,6 @@ struct wlsc_compositor { void (*destroy)(struct wlsc_compositor *ec); int (*authenticate)(struct wlsc_compositor *c, uint32_t id); - void (*present)(struct wlsc_compositor *c); struct wl_buffer *(*create_buffer)(struct wlsc_compositor *c, int32_t width, int32_t height, int32_t stride, struct wl_visual *visual, @@ -151,6 +152,7 @@ struct wlsc_surface { struct wlsc_matrix matrix_inv; struct wl_visual *visual; struct wl_buffer *buffer; + struct wlsc_output *output; enum wlsc_surface_map_type map_type; struct wlsc_output *fullscreen_output; }; @@ -180,11 +182,14 @@ notify_keyboard_focus(struct wl_input_device *device, struct wl_array *keys); void -wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs); +wlsc_output_finish_frame(struct wlsc_output *output, int msecs); void wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); void +wlsc_surface_assign_output(struct wlsc_surface *surface); + +void wlsc_surface_damage(struct wlsc_surface *surface); void diff --git a/compositor/shell.c b/compositor/shell.c index a19d3db..8ed7d2c 100644 --- a/compositor/shell.c +++ b/compositor/shell.c @@ -43,6 +43,7 @@ move_grab_motion(struct wl_grab *grab, wlsc_surface_damage(es); es->x = x + move->dx; es->y = y + move->dy; + wlsc_surface_assign_output(es); wlsc_surface_update_matrix(es); wlsc_surface_damage(es); } -- 2.7.4