Use pixman regions to reduce repainting
authorKristian Høgsberg <krh@bitplanet.net>
Sun, 13 Feb 2011 18:00:51 +0000 (13:00 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Sun, 13 Feb 2011 18:26:39 +0000 (13:26 -0500)
For now, we just use glScissor and clip to the extent of the damage region,
but we can do even better by clipping the repaint to the region rectangles.

compositor/compositor.c
compositor/compositor.h
compositor/shell.c
configure.ac

index 535b3f1..ec0d727 100644 (file)
@@ -163,6 +163,27 @@ wlsc_surface_create(struct wlsc_compositor *compositor,
        return surface;
 }
 
+void
+wlsc_surface_damage_rectangle(struct wlsc_surface *surface,
+                             int32_t x, int32_t y,
+                             int32_t width, int32_t height)
+{
+       struct wlsc_compositor *compositor = surface->compositor;
+
+       pixman_region32_union_rect(&compositor->damage_region,
+                                  &compositor->damage_region,
+                                  surface->x + x, surface->y + y,
+                                  width, height);
+       wlsc_compositor_schedule_repaint(compositor);
+}
+
+void
+wlsc_surface_damage(struct wlsc_surface *surface)
+{
+       wlsc_surface_damage_rectangle(surface, 0, 0,
+                                     surface->width, surface->height);
+}
+
 uint32_t
 get_time(void)
 {
@@ -178,10 +199,11 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
 {
        struct wlsc_surface *surface =
                container_of(resource, struct wlsc_surface, surface.resource);
-       struct wlsc_compositor *compositor = surface->compositor;
        struct wl_listener *l, *next;
        uint32_t time;
 
+       wlsc_surface_damage(surface);
+
        wl_list_remove(&surface->link);
        glDeleteTextures(1, &surface->texture);
 
@@ -191,8 +213,6 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
                l->func(l, &surface->surface, time);
 
        free(surface);
-
-       wlsc_compositor_schedule_repaint(compositor);
 }
 
 uint32_t *
@@ -407,9 +427,28 @@ wlsc_output_repaint(struct wlsc_output *output)
        struct wlsc_compositor *ec = output->compositor;
        struct wlsc_surface *es;
        struct wlsc_input_device *eid;
+       pixman_region32_t new_damage, total_damage;
+       pixman_box32_t *extents;
 
        glViewport(0, 0, output->width, output->height);
 
+       pixman_region32_init(&new_damage);
+       pixman_region32_init(&total_damage);
+       pixman_region32_intersect_rect(&new_damage,
+                                      &ec->damage_region,
+                                      output->x, output->y,
+                                      output->width, output->height);
+       pixman_region32_subtract(&ec->damage_region,
+                                &ec->damage_region, &new_damage);
+       pixman_region32_union(&total_damage, &new_damage,
+                             &output->previous_damage_region);
+       pixman_region32_copy(&output->previous_damage_region, &new_damage);
+
+       extents = pixman_region32_extents(&total_damage);
+       glEnable(GL_SCISSOR_TEST);
+       glScissor(extents->x1, extents->y1,
+                 extents->x2 - extents->x1, extents->y2 - extents->y1);
+
        es = container_of(ec->surface_list.next, struct wlsc_surface, link);
        if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN &&
            es->fullscreen_output == output) {
@@ -483,6 +522,12 @@ surface_attach(struct wl_client *client,
 {
        struct wlsc_surface *es = (struct wlsc_surface *) surface;
 
+       /* FIXME: This damages the entire old surface, but we should
+        * really just damage the part that's no longer covered by the
+        * surface.  Anything covered by the new surface will be
+        * damaged by the client. */
+       wlsc_surface_damage(es);
+
        buffer->attach(buffer, surface);
        es->buffer = buffer;
        es->x += x;
@@ -517,7 +562,7 @@ surface_map_toplevel(struct wl_client *client,
                break;
        }
 
-       wlsc_compositor_schedule_repaint(es->compositor);
+       wlsc_surface_damage(es);
        es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
 }
 
@@ -544,7 +589,7 @@ surface_map_transient(struct wl_client *client,
        es->y = pes->y + y;
 
        wlsc_surface_update_matrix(es);
-       wlsc_compositor_schedule_repaint(es->compositor);
+       wlsc_surface_damage(es);
        es->map_type = WLSC_SURFACE_MAP_TRANSIENT;
 }
 
@@ -577,7 +622,7 @@ surface_map_fullscreen(struct wl_client *client, struct wl_surface *surface)
        es->y = (output->height - es->height) / 2;
        es->fullscreen_output = output;
        wlsc_surface_update_matrix(es);
-       wlsc_compositor_schedule_repaint(es->compositor);
+       wlsc_surface_damage(es);
        es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
 }
 
@@ -589,7 +634,8 @@ surface_damage(struct wl_client *client,
        struct wlsc_surface *es = (struct wlsc_surface *) surface;
 
        es->buffer->damage(es->buffer, surface, x, y, width, height);
-       wlsc_compositor_schedule_repaint(es->compositor);
+
+       wlsc_surface_damage_rectangle(es, x, y, width, height);
 }
 
 const static struct wl_surface_interface surface_interface = {
@@ -605,8 +651,7 @@ static void
 wlsc_input_device_attach(struct wlsc_input_device *device,
                         struct wl_buffer *buffer, int x, int y)
 {
-       struct wlsc_compositor *ec =
-               (struct wlsc_compositor *) device->input_device.compositor;
+       wlsc_surface_damage(device->sprite);
 
        buffer->attach(buffer, &device->sprite->surface);
        device->hotspot_x = x;
@@ -618,7 +663,7 @@ wlsc_input_device_attach(struct wlsc_input_device *device,
        device->sprite->height = buffer->height;
        wlsc_surface_update_matrix(device->sprite);
 
-       wlsc_compositor_schedule_repaint(ec);
+       wlsc_surface_damage(device->sprite);
 }
 
 
@@ -770,11 +815,13 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
                                             time, x, y, sx, sy);
        }
 
+       wlsc_surface_damage(wd->sprite);
+
        wd->sprite->x = device->x - wd->hotspot_x;
        wd->sprite->y = device->y - wd->hotspot_y;
        wlsc_surface_update_matrix(wd->sprite);
 
-       wlsc_compositor_schedule_repaint(ec);
+       wlsc_surface_damage(wd->sprite);
 }
 
 static void
@@ -854,6 +901,7 @@ wlsc_switcher_next(struct wlsc_switcher *switcher)
 {
        struct wl_list *l;
 
+       wlsc_surface_damage(switcher->current);
        l = switcher->current->link.next;
        if (l == &switcher->compositor->surface_list)
                l = switcher->compositor->surface_list.next;
@@ -861,7 +909,7 @@ wlsc_switcher_next(struct wlsc_switcher *switcher)
        wl_list_remove(&switcher->listener.link);
        wl_list_insert(switcher->current->surface.destroy_listener_list.prev,
                       &switcher->listener.link);
-       wlsc_compositor_schedule_repaint(switcher->compositor);
+       wlsc_surface_damage(switcher->current);
 }
 
 static void
@@ -1006,7 +1054,7 @@ notify_pointer_focus(struct wl_input_device *device,
                compositor->focus = 0;
        }
 
-       wlsc_compositor_schedule_repaint(compositor);
+       wlsc_surface_damage(wd->sprite);
 }
 
 void
@@ -1213,6 +1261,8 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
        output->width = width;
        output->height = height;
 
+       pixman_region32_init(&output->previous_damage_region);
+
        output->background =
                background_create(output, option_background);
 
@@ -1227,6 +1277,10 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
        wl_display_add_object(c->wl_display, &output->object);
        wl_display_add_global(c->wl_display, &output->object,
                              wlsc_output_post_geometry);
+
+       pixman_region32_union_rect(&c->damage_region,
+                                  &c->damage_region,
+                                  x, y, width, height);
 }
 
 int
@@ -1266,6 +1320,7 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display)
 
        loop = wl_display_get_event_loop(ec->wl_display);
        ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
+       pixman_region32_init(&ec->damage_region);
        wlsc_compositor_schedule_repaint(ec);
 
        return 0;
index dfe9951..67d9f2a 100644 (file)
@@ -22,6 +22,7 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 #include <libudev.h>
+#include <pixman.h>
 #include "wayland-server.h"
 #include "wayland-util.h"
 
@@ -47,6 +48,7 @@ struct wlsc_output {
        struct wlsc_surface *background;
        struct wlsc_matrix matrix;
        int32_t x, y, width, height;
+       pixman_region32_t previous_damage_region;
 };
 
 enum wlsc_pointer_type {
@@ -109,6 +111,7 @@ struct wlsc_compositor {
        int repaint_needed;
        int repaint_on_timeout;
        struct timespec previous_swap;
+       pixman_region32_t damage_region;
 
        struct wlsc_switcher *switcher;
        uint32_t focus;
@@ -182,6 +185,14 @@ void
 wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor);
 
 void
+wlsc_surface_damage(struct wlsc_surface *surface);
+
+void
+wlsc_surface_damage_rectangle(struct wlsc_surface *surface,
+                             int32_t x, int32_t y,
+                             int32_t width, int32_t height);
+
+void
 wlsc_input_device_set_pointer_image(struct wlsc_input_device *device,
                                    enum wlsc_pointer_type type);
 struct wlsc_surface *
index 1ff32e9..a19d3db 100644 (file)
@@ -40,9 +40,11 @@ move_grab_motion(struct wl_grab *grab,
        struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
        struct wlsc_surface *es = move->surface;
 
+       wlsc_surface_damage(es);
        es->x = x + move->dx;
        es->y = y + move->dy;
        wlsc_surface_update_matrix(es);
+       wlsc_surface_damage(es);
 }
 
 static void
index b671722..48b9169 100644 (file)
@@ -23,7 +23,7 @@ PKG_PROG_PKG_CONFIG()
 PKG_CHECK_MODULES(FFI, [libffi])
 
 PKG_CHECK_MODULES(COMPOSITOR,
-                 [egl >= 7.10 glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.23] xcb-dri2 xcb-xfixes)
+                 [egl >= 7.10 glesv2 gdk-pixbuf-2.0 libudev >= 136 libdrm >= 2.4.23] pixman-1 xcb-dri2 xcb-xfixes)
 PKG_CHECK_MODULES(GLES2, [egl >= 7.10 glesv2])
 PKG_CHECK_MODULES(CLIENT, [egl >= 7.10 gl cairo >= 1.10.0 gdk-pixbuf-2.0 glib-2.0 gobject-2.0 xkbcommon])
 PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0 gio-2.0],