Support per surface frame events
authorBenjamin Franzke <benjaminfranzke@googlemail.com>
Mon, 14 Mar 2011 11:07:26 +0000 (12:07 +0100)
committerBenjamin Franzke <benjaminfranzke@googlemail.com>
Thu, 17 Mar 2011 10:54:35 +0000 (11:54 +0100)
This fixes tearing with multi head.

12 files changed:
clients/gears.c
clients/resizor.c
clients/simple-client.c
clients/smoke.c
clients/window.c
clients/window.h
compositor/compositor-drm.c
compositor/compositor-wayland.c
compositor/compositor-x11.c
compositor/compositor.c
compositor/compositor.h
compositor/shell.c

index 8496abb..5c2b3cf 100644 (file)
@@ -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;
index 0ac02f6..fc5dedd 100644 (file)
@@ -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;
        }
 }
index 89718df..01afaae 100644 (file)
@@ -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)
index 0710b3a..32ca0c0 100644 (file)
@@ -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);
index 0c93b9c..ec1714e 100644 (file)
@@ -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)
 {
index 7073f4a..c5285f7 100644 (file)
@@ -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);
 
index aa58a31..c769874 100644 (file)
@@ -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;
 
index 524a25c..097b23e 100644 (file)
@@ -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 */
index ba593c1..f837a6a 100644 (file)
@@ -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 */
index 23465da..90fd51c 100644 (file)
@@ -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;
index 637fde0..6a392fc 100644 (file)
@@ -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
index a19d3db..8ed7d2c 100644 (file)
@@ -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);
 }