From 8ea818fb00aa45fb6e9ff83059778502cef82d1b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 14 Sep 2012 16:12:03 +0300 Subject: [PATCH] compositor: Generalize output previous damage into per buffer damage This is a more generic fix for the issue solved in 4f521731 where damage obscured by overlays could be lost in one of the output buffers due to rapid move of a surface in an overlay plane. This changes the renderer so it keeps track of the damage in each buffer. Every time a new frame is drawn, the damage of the frame is added to all the buffers and the rendered regions are cleared from the current buffer's damage. --- src/compositor.c | 30 ++++++++++++++---------------- src/compositor.h | 3 ++- src/gles2-renderer.c | 17 ++++++++++++++--- src/screenshooter.c | 15 ++++++++++++--- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 8cb8a3f6..bda13818 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -863,7 +863,7 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs) struct weston_animation *animation, *next; struct weston_frame_callback *cb, *cnext; struct wl_list frame_callback_list; - pixman_region32_t opaque, output_damage, new_damage; + pixman_region32_t opaque, output_damage; weston_compositor_update_drag_surfaces(ec); @@ -896,21 +896,10 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs) pixman_region32_fini(&opaque); pixman_region32_init(&output_damage); - - pixman_region32_init(&new_damage); - pixman_region32_copy(&new_damage, &ec->primary_plane.damage); - - pixman_region32_union(&ec->primary_plane.damage, - &ec->primary_plane.damage, - &output->previous_damage); - - pixman_region32_intersect(&output->previous_damage, - &new_damage, &output->region); - pixman_region32_intersect(&output_damage, &ec->primary_plane.damage, &output->region); - - pixman_region32_fini(&new_damage); + pixman_region32_subtract(&ec->primary_plane.damage, + &ec->primary_plane.damage, &output->region); if (output->dirty) weston_output_update_matrix(output); @@ -2521,9 +2510,13 @@ WL_EXPORT void weston_output_destroy(struct weston_output *output) { struct weston_compositor *c = output->compositor; + int i; pixman_region32_fini(&output->region); - pixman_region32_fini(&output->previous_damage); + + for (i = 0; i < 2; i++) + pixman_region32_fini(&output->buffer_damage[i]); + output->compositor->output_id_pool &= ~(1 << output->id); wl_display_remove_global(c->wl_display, output->global); @@ -2647,10 +2640,15 @@ weston_output_transform_init(struct weston_output *output, uint32_t transform) WL_EXPORT void weston_output_move(struct weston_output *output, int x, int y) { + int i; + output->x = x; output->y = y; - pixman_region32_init(&output->previous_damage); + output->current_buffer = 0; + for (i = 0; i < 2; i++) + pixman_region32_init(&output->buffer_damage[i]); + pixman_region32_init_rect(&output->region, x, y, output->width, output->height); diff --git a/src/compositor.h b/src/compositor.h index 6716bdc6..47609934 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -160,7 +160,8 @@ struct weston_output { int32_t mm_width, mm_height; struct weston_border border; pixman_region32_t region; - pixman_region32_t previous_damage; + int current_buffer; + pixman_region32_t buffer_damage[2]; int repaint_needed; int repaint_scheduled; struct weston_output_zoom zoom; diff --git a/src/gles2-renderer.c b/src/gles2-renderer.c index 0e8b8cef..761f4fe6 100644 --- a/src/gles2-renderer.c +++ b/src/gles2-renderer.c @@ -612,6 +612,7 @@ draw_surface(struct weston_surface *es, struct weston_output *output, pixman_region32_t repaint; /* non-opaque region in surface coordinates: */ pixman_region32_t surface_blend; + pixman_region32_t *buffer_damage; GLint filter; int i; @@ -623,8 +624,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output, if (!pixman_region32_not_empty(&repaint)) goto out; - pixman_region32_subtract(&ec->primary_plane.damage, - &ec->primary_plane.damage, &repaint); + buffer_damage = &output->buffer_damage[output->current_buffer]; + pixman_region32_subtract(buffer_damage, buffer_damage, &repaint); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -702,7 +703,7 @@ gles2_renderer_repaint_output(struct weston_output *output, struct weston_compositor *compositor = output->compositor; EGLBoolean ret; static int errored; - int32_t width, height; + int32_t width, height, i; width = output->current->width + output->border.left + output->border.right; @@ -736,6 +737,14 @@ gles2_renderer_repaint_output(struct weston_output *output, pixman_region32_fini(&undamaged); } + for (i = 0; i < 2; i++) + pixman_region32_union(&output->buffer_damage[i], + &output->buffer_damage[i], + output_damage); + + pixman_region32_union(output_damage, output_damage, + &output->buffer_damage[output->current_buffer]); + repaint_surfaces(output, output_damage); wl_signal_emit(&output->frame_signal, output); @@ -747,6 +756,8 @@ gles2_renderer_repaint_output(struct weston_output *output, print_egl_error_state(); } + output->current_buffer ^= 1; + } static void diff --git a/src/screenshooter.c b/src/screenshooter.c index ba80ce55..ffcc9706 100644 --- a/src/screenshooter.c +++ b/src/screenshooter.c @@ -261,7 +261,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) struct weston_output *output = data; uint32_t msecs = output->frame_time; pixman_box32_t *r; - pixman_region32_t damage; + pixman_region32_t damage, *previous_damage; int i, j, k, n, width, height, run, stride; uint32_t delta, prev, *d, *s, *p, next; struct { @@ -270,9 +270,18 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data) } header; struct iovec v[2]; + /* When recording, this will be exactly the region that was repainted + * in this frame. Since overlays are disabled, the whole primary plane + * damage is rendered. For the first frame, the whole output will be + * damaged and that damage will be added to both buffers causing the + * non-current buffer damage to be while output. Rendering will clear + * all the damage in the current buffer so in the next frame (when + * that is non-current) the only damage left will be the one added + * from the primary plane. */ + previous_damage = &output->buffer_damage[output->current_buffer ^ 1]; + pixman_region32_init(&damage); - pixman_region32_intersect(&damage, &output->region, - &output->previous_damage); + pixman_region32_intersect(&damage, &output->region, previous_damage); r = pixman_region32_rectangles(&damage, &n); if (n == 0)