diff options
author | Kristian Høgsberg <krh@bitplanet.net> | 2011-05-16 09:37:15 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2011-05-16 09:37:15 -0400 |
commit | 81006c69a479e65eee1e89c9a5d8cc8ec67fd531 (patch) | |
tree | 547b981ba6cd73e803dc30f2f8c99c59164b7d53 | |
parent | 8f386ce1621247a3dfa8829a3c180f7a37aa0e8d (diff) |
compositor: Clip out damage obscured by opaque surfacessurface-damage
-rw-r--r-- | compositor/compositor.c | 153 | ||||
-rw-r--r-- | compositor/compositor.h | 6 |
2 files changed, 98 insertions, 61 deletions
diff --git a/compositor/compositor.c b/compositor/compositor.c index 00ffc91b..398de5ed 100644 --- a/compositor/compositor.c +++ b/compositor/compositor.c @@ -181,6 +181,9 @@ wlsc_surface_create(struct wlsc_compositor *compositor, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + pixman_region32_init(&surface->damage); + pixman_region32_init(&surface->lower_damage); + surface->compositor = compositor; surface->visual = NULL; surface->image = EGL_NO_IMAGE_KHR; @@ -202,8 +205,8 @@ wlsc_surface_damage_rectangle(struct wlsc_surface *surface, { struct wlsc_compositor *compositor = surface->compositor; - pixman_region32_union_rect(&compositor->damage_region, - &compositor->damage_region, + pixman_region32_union_rect(&surface->damage, + &surface->damage, surface->x + x, surface->y + y, width, height); wlsc_compositor_schedule_repaint(compositor); @@ -216,6 +219,15 @@ wlsc_surface_damage(struct wlsc_surface *surface) surface->width, surface->height); } +WL_EXPORT void +wlsc_surface_damage_below(struct wlsc_surface *surface) +{ + pixman_region32_union_rect(&surface->lower_damage, + &surface->lower_damage, + 0, 0, surface->width, surface->height); + wlsc_compositor_schedule_repaint(surface->compositor); +} + WL_EXPORT uint32_t wlsc_compositor_get_time(void) { @@ -233,7 +245,7 @@ destroy_surface(struct wl_resource *resource, struct wl_client *client) container_of(resource, struct wlsc_surface, surface.resource); struct wlsc_compositor *compositor = surface->compositor; - wlsc_surface_damage(surface); + wlsc_surface_damage_below(surface); wl_list_remove(&surface->link); if (surface->saved_texture == 0) @@ -433,6 +445,13 @@ texture_region(struct wlsc_surface *es, pixman_region32_t *region) inv_height = 1.0 / es->height; for (i = 0; i < n; i++, v += 16, p += 6) { + fprintf(stderr, "texture rect: %d,%d-%d,%d (%dx%d)\n", + rectangles[i].x1, rectangles[i].y1, + rectangles[i].x2, rectangles[i].y2, + + rectangles[i].x2 - rectangles[i].x1, + rectangles[i].y2 - rectangles[i].y1); + v[ 0] = rectangles[i].x1; v[ 1] = rectangles[i].y1; v[ 2] = (GLfloat) (rectangles[i].x1 - es->x) * inv_width; @@ -514,15 +533,21 @@ wlsc_surface_draw(struct wlsc_surface *es, struct wlsc_output *output, pixman_region32_t *clip) { struct wlsc_compositor *ec = es->compositor; - GLfloat *v; pixman_region32_t repaint; + GLfloat *v; int n; pixman_region32_init_rect(&repaint, es->x, es->y, es->width, es->height); pixman_region32_intersect(&repaint, &repaint, clip); - if (!pixman_region32_not_empty(&repaint)) + pixman_region32_intersect(&repaint, &repaint, &output->region); + + if (!pixman_region32_not_empty(&repaint)) { + pixman_region32_fini(&repaint); return; + } + + fprintf(stderr, "draw surface %p\n", es); if (es->visual == &ec->compositor.argb_visual) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -549,6 +574,7 @@ wlsc_surface_draw(struct wlsc_surface *es, ec->vertices.size = 0; ec->indices.size = 0; + pixman_region32_fini(&repaint); } @@ -599,8 +625,8 @@ wlsc_output_damage(struct wlsc_output *output) { struct wlsc_compositor *compositor = output->compositor; - pixman_region32_union_rect(&compositor->damage_region, - &compositor->damage_region, + pixman_region32_union_rect(&compositor->pending_damage, + &compositor->pending_damage, output->x, output->y, output->width, output->height); wlsc_compositor_schedule_repaint(compositor); @@ -659,12 +685,50 @@ fade_output(struct wlsc_output *output, } static void +push_down_damage(struct wlsc_compositor *ec) +{ + struct wlsc_surface *es; + + wl_list_for_each(es, &ec->surface_list, link) { + pixman_region32_union(&es->damage, &es->damage, + &ec->pending_damage); + pixman_region32_union(&ec->pending_damage, + &ec->pending_damage, + &es->lower_damage); + pixman_region32_fini(&es->lower_damage); + pixman_region32_init(&es->lower_damage); + } + pixman_region32_fini(&ec->pending_damage); + pixman_region32_init(&ec->pending_damage); +} + +static void +clip_surface_damage(struct wlsc_compositor *ec) +{ + struct wlsc_surface *es; + pixman_region32_t opaque, visible; + + pixman_region32_init(&opaque); + wl_list_for_each(es, &ec->surface_list, link) { + pixman_region32_init_rect(&visible, + es->x, es->y, es->width, es->height); + pixman_region32_subtract(&visible, &visible, &opaque); + pixman_region32_intersect(&es->damage, &es->damage, &visible); + + if (es->visual == &ec->compositor.rgb_visual) + pixman_region32_union(&opaque, &opaque, &visible); + pixman_region32_fini(&visible); + } + pixman_region32_fini(&opaque); +} + +static void wlsc_output_repaint(struct wlsc_output *output) { struct wlsc_compositor *ec = output->compositor; struct wlsc_surface *es; struct wlsc_input_device *eid, *hw_cursor; - pixman_region32_t new_damage, total_damage; + pixman_region32_t damage; output->prepare_render(output); @@ -675,18 +739,6 @@ wlsc_output_repaint(struct wlsc_output *output) 1, GL_FALSE, output->matrix.d); glUniform1i(ec->texture_shader.tex_uniform, 0); - 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); - hw_cursor = NULL; if (ec->focus && ec->fade.spring.current < 0.001) { hw_cursor = (struct wlsc_input_device *) ec->input_device; @@ -699,50 +751,31 @@ wlsc_output_repaint(struct wlsc_output *output) es = container_of(ec->surface_list.next, struct wlsc_surface, link); if (es->visual == &ec->compositor.rgb_visual && hw_cursor) { - if (output->prepare_scanout_surface(output, es) == 0) { - /* We're drawing nothing now, - * draw the damaged regions later. */ - pixman_region32_union(&ec->damage_region, - &ec->damage_region, - &total_damage); + if (output->prepare_scanout_surface(output, es) == 0) return; - } } - if (es->fullscreen_output == output) { - if (es->width < output->width || - es->height < output->height) - glClear(GL_COLOR_BUFFER_BIT); - wlsc_surface_draw(es, output, &total_damage); - } else { - if (output->background) - wlsc_surface_draw(output->background, - output, &total_damage); - else - fade_output(output, 1.0, &total_damage); - - glUseProgram(ec->texture_shader.program); - wl_list_for_each_reverse(es, &ec->surface_list, link) { - if (ec->overlay == es) - continue; + glUseProgram(ec->texture_shader.program); + pixman_region32_init(&damage); + wl_list_for_each_reverse(es, &ec->surface_list, link) { + pixman_region32_union(&damage, &damage, &es->damage); + pixman_region32_subtract(&es->damage, + &es->damage, &output->region); - wlsc_surface_draw(es, output, &total_damage); - } + wlsc_surface_draw(es, output, &damage); } - - if (ec->overlay) - wlsc_surface_draw(ec->overlay, output, &total_damage); + pixman_region32_fini(&damage); if (ec->focus) wl_list_for_each(eid, &ec->input_device_list, link) { if (&eid->input_device != ec->input_device || eid != hw_cursor) wlsc_surface_draw(eid->sprite, output, - &total_damage); + &output->region); } if (ec->fade.spring.current > 0.001) - fade_output(output, ec->fade.spring.current, &total_damage); + fade_output(output, ec->fade.spring.current, &damage); } static int @@ -751,6 +784,9 @@ repaint(void *data) struct wlsc_compositor *ec = data; struct wlsc_output *output; int repainted_all_outputs = 1; + + push_down_damage(ec); + clip_surface_damage(ec); wl_list_for_each(output, &ec->output_list, link) { if (!output->repaint_needed) @@ -858,7 +894,7 @@ surface_attach(struct wl_client *client, * 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); + wlsc_surface_damage_below(es); switch (es->map_type) { case WLSC_SURFACE_MAP_FULLSCREEN: @@ -996,7 +1032,7 @@ static void wlsc_input_device_attach(struct wlsc_input_device *device, int x, int y, int width, int height) { - wlsc_surface_damage(device->sprite); + wlsc_surface_damage_below(device->sprite); device->hotspot_x = x; device->hotspot_y = y; @@ -1235,7 +1271,7 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y) time, x, y, sx, sy); } - wlsc_surface_damage(wd->sprite); + wlsc_surface_damage_below(wd->sprite); wd->sprite->x = device->x - wd->hotspot_x; wd->sprite->y = device->y - wd->hotspot_y; @@ -1695,8 +1731,6 @@ wlsc_output_move(struct wlsc_output *output, int x, int y) output->background->y = y; } - pixman_region32_init(&output->previous_damage_region); - wlsc_matrix_init(&output->matrix); wlsc_matrix_translate(&output->matrix, -output->x - output->width / 2.0, @@ -1707,9 +1741,10 @@ wlsc_output_move(struct wlsc_output *output, int x, int y) 2.0 / output->width, flip * 2.0 / output->height, 1); - pixman_region32_union_rect(&c->damage_region, - &c->damage_region, - x, y, output->width, output->height); + pixman_region32_init_rect(&output->region, + x, y, output->width, output->height); + pixman_region32_union(&c->pending_damage, + &c->pending_damage, &output->region); } WL_EXPORT void @@ -1859,7 +1894,7 @@ wlsc_compositor_init(struct wlsc_compositor *ec, struct wl_display *display) wl_event_source_timer_update(ec->idle_source, option_idle_time * 1000); ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec); - pixman_region32_init(&ec->damage_region); + pixman_region32_init(&ec->pending_damage); wlsc_compositor_schedule_repaint(ec); return 0; diff --git a/compositor/compositor.h b/compositor/compositor.h index 2546d58f..61ece260 100644 --- a/compositor/compositor.h +++ b/compositor/compositor.h @@ -59,8 +59,8 @@ struct wlsc_output { struct wlsc_compositor *compositor; struct wlsc_surface *background; struct wlsc_matrix matrix; + pixman_region32_t region; int32_t x, y, width, height; - pixman_region32_t previous_damage_region; uint32_t flags; int repaint_needed; int finished; @@ -178,7 +178,7 @@ struct wlsc_compositor { struct wl_event_source *timer_source; int repaint_on_timeout; struct timespec previous_swap; - pixman_region32_t damage_region; + pixman_region32_t pending_damage; struct wl_array vertices, indices; struct wlsc_surface *overlay; @@ -223,6 +223,8 @@ struct wlsc_surface { struct wl_surface surface; struct wlsc_compositor *compositor; GLuint texture, saved_texture; + pixman_region32_t damage; + pixman_region32_t lower_damage; int32_t x, y, width, height; int32_t pitch; int32_t saved_x, saved_y; |