Use pixman regions to reduce repainting

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.
dev
Kristian Høgsberg 14 years ago
parent 9c7a8cc663
commit 31bd6c7ab1
  1. 81
      compositor/compositor.c
  2. 11
      compositor/compositor.h
  3. 2
      compositor/shell.c
  4. 2
      configure.ac

@ -163,6 +163,27 @@ wlsc_surface_create(struct wlsc_compositor *compositor,
return surface; 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 uint32_t
get_time(void) get_time(void)
{ {
@ -178,10 +199,11 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
{ {
struct wlsc_surface *surface = struct wlsc_surface *surface =
container_of(resource, struct wlsc_surface, surface.resource); container_of(resource, struct wlsc_surface, surface.resource);
struct wlsc_compositor *compositor = surface->compositor;
struct wl_listener *l, *next; struct wl_listener *l, *next;
uint32_t time; uint32_t time;
wlsc_surface_damage(surface);
wl_list_remove(&surface->link); wl_list_remove(&surface->link);
glDeleteTextures(1, &surface->texture); glDeleteTextures(1, &surface->texture);
@ -191,8 +213,6 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client)
l->func(l, &surface->surface, time); l->func(l, &surface->surface, time);
free(surface); free(surface);
wlsc_compositor_schedule_repaint(compositor);
} }
uint32_t * uint32_t *
@ -407,9 +427,28 @@ wlsc_output_repaint(struct wlsc_output *output)
struct wlsc_compositor *ec = output->compositor; struct wlsc_compositor *ec = output->compositor;
struct wlsc_surface *es; struct wlsc_surface *es;
struct wlsc_input_device *eid; struct wlsc_input_device *eid;
pixman_region32_t new_damage, total_damage;
pixman_box32_t *extents;
glViewport(0, 0, output->width, output->height); 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); es = container_of(ec->surface_list.next, struct wlsc_surface, link);
if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN && if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN &&
es->fullscreen_output == output) { es->fullscreen_output == output) {
@ -483,6 +522,12 @@ surface_attach(struct wl_client *client,
{ {
struct wlsc_surface *es = (struct wlsc_surface *) surface; 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); buffer->attach(buffer, surface);
es->buffer = buffer; es->buffer = buffer;
es->x += x; es->x += x;
@ -517,7 +562,7 @@ surface_map_toplevel(struct wl_client *client,
break; break;
} }
wlsc_compositor_schedule_repaint(es->compositor); wlsc_surface_damage(es);
es->map_type = WLSC_SURFACE_MAP_TOPLEVEL; es->map_type = WLSC_SURFACE_MAP_TOPLEVEL;
} }
@ -544,7 +589,7 @@ surface_map_transient(struct wl_client *client,
es->y = pes->y + y; es->y = pes->y + y;
wlsc_surface_update_matrix(es); wlsc_surface_update_matrix(es);
wlsc_compositor_schedule_repaint(es->compositor); wlsc_surface_damage(es);
es->map_type = WLSC_SURFACE_MAP_TRANSIENT; 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->y = (output->height - es->height) / 2;
es->fullscreen_output = output; es->fullscreen_output = output;
wlsc_surface_update_matrix(es); wlsc_surface_update_matrix(es);
wlsc_compositor_schedule_repaint(es->compositor); wlsc_surface_damage(es);
es->map_type = WLSC_SURFACE_MAP_FULLSCREEN; 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; struct wlsc_surface *es = (struct wlsc_surface *) surface;
es->buffer->damage(es->buffer, surface, x, y, width, height); 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 = { const static struct wl_surface_interface surface_interface = {
@ -605,8 +651,7 @@ static void
wlsc_input_device_attach(struct wlsc_input_device *device, wlsc_input_device_attach(struct wlsc_input_device *device,
struct wl_buffer *buffer, int x, int y) struct wl_buffer *buffer, int x, int y)
{ {
struct wlsc_compositor *ec = wlsc_surface_damage(device->sprite);
(struct wlsc_compositor *) device->input_device.compositor;
buffer->attach(buffer, &device->sprite->surface); buffer->attach(buffer, &device->sprite->surface);
device->hotspot_x = x; device->hotspot_x = x;
@ -618,7 +663,7 @@ wlsc_input_device_attach(struct wlsc_input_device *device,
device->sprite->height = buffer->height; device->sprite->height = buffer->height;
wlsc_surface_update_matrix(device->sprite); 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); time, x, y, sx, sy);
} }
wlsc_surface_damage(wd->sprite);
wd->sprite->x = device->x - wd->hotspot_x; wd->sprite->x = device->x - wd->hotspot_x;
wd->sprite->y = device->y - wd->hotspot_y; wd->sprite->y = device->y - wd->hotspot_y;
wlsc_surface_update_matrix(wd->sprite); wlsc_surface_update_matrix(wd->sprite);
wlsc_compositor_schedule_repaint(ec); wlsc_surface_damage(wd->sprite);
} }
static void static void
@ -854,6 +901,7 @@ wlsc_switcher_next(struct wlsc_switcher *switcher)
{ {
struct wl_list *l; struct wl_list *l;
wlsc_surface_damage(switcher->current);
l = switcher->current->link.next; l = switcher->current->link.next;
if (l == &switcher->compositor->surface_list) if (l == &switcher->compositor->surface_list)
l = switcher->compositor->surface_list.next; 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_remove(&switcher->listener.link);
wl_list_insert(switcher->current->surface.destroy_listener_list.prev, wl_list_insert(switcher->current->surface.destroy_listener_list.prev,
&switcher->listener.link); &switcher->listener.link);
wlsc_compositor_schedule_repaint(switcher->compositor); wlsc_surface_damage(switcher->current);
} }
static void static void
@ -1006,7 +1054,7 @@ notify_pointer_focus(struct wl_input_device *device,
compositor->focus = 0; compositor->focus = 0;
} }
wlsc_compositor_schedule_repaint(compositor); wlsc_surface_damage(wd->sprite);
} }
void void
@ -1213,6 +1261,8 @@ wlsc_output_init(struct wlsc_output *output, struct wlsc_compositor *c,
output->width = width; output->width = width;
output->height = height; output->height = height;
pixman_region32_init(&output->previous_damage_region);
output->background = output->background =
background_create(output, option_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_object(c->wl_display, &output->object);
wl_display_add_global(c->wl_display, &output->object, wl_display_add_global(c->wl_display, &output->object,
wlsc_output_post_geometry); wlsc_output_post_geometry);
pixman_region32_union_rect(&c->damage_region,
&c->damage_region,
x, y, width, height);
} }
int 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); loop = wl_display_get_event_loop(ec->wl_display);
ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec); ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec);
pixman_region32_init(&ec->damage_region);
wlsc_compositor_schedule_repaint(ec); wlsc_compositor_schedule_repaint(ec);
return 0; return 0;

@ -22,6 +22,7 @@
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include <libudev.h> #include <libudev.h>
#include <pixman.h>
#include "wayland-server.h" #include "wayland-server.h"
#include "wayland-util.h" #include "wayland-util.h"
@ -47,6 +48,7 @@ struct wlsc_output {
struct wlsc_surface *background; struct wlsc_surface *background;
struct wlsc_matrix matrix; struct wlsc_matrix matrix;
int32_t x, y, width, height; int32_t x, y, width, height;
pixman_region32_t previous_damage_region;
}; };
enum wlsc_pointer_type { enum wlsc_pointer_type {
@ -109,6 +111,7 @@ struct wlsc_compositor {
int repaint_needed; int repaint_needed;
int repaint_on_timeout; int repaint_on_timeout;
struct timespec previous_swap; struct timespec previous_swap;
pixman_region32_t damage_region;
struct wlsc_switcher *switcher; struct wlsc_switcher *switcher;
uint32_t focus; uint32_t focus;
@ -181,6 +184,14 @@ wlsc_compositor_finish_frame(struct wlsc_compositor *compositor, int msecs);
void void
wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor); 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 void
wlsc_input_device_set_pointer_image(struct wlsc_input_device *device, wlsc_input_device_set_pointer_image(struct wlsc_input_device *device,
enum wlsc_pointer_type type); enum wlsc_pointer_type type);

@ -40,9 +40,11 @@ move_grab_motion(struct wl_grab *grab,
struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab; struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
struct wlsc_surface *es = move->surface; struct wlsc_surface *es = move->surface;
wlsc_surface_damage(es);
es->x = x + move->dx; es->x = x + move->dx;
es->y = y + move->dy; es->y = y + move->dy;
wlsc_surface_update_matrix(es); wlsc_surface_update_matrix(es);
wlsc_surface_damage(es);
} }
static void static void

@ -23,7 +23,7 @@ PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(FFI, [libffi]) PKG_CHECK_MODULES(FFI, [libffi])
PKG_CHECK_MODULES(COMPOSITOR, 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(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(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], PKG_CHECK_MODULES(POPPLER, [poppler-glib gdk-2.0 gio-2.0],

Loading…
Cancel
Save