When we zoom or scale an output it's possible for a single buffer pixel to be stretched over multiple output pixels.
When this happens, if a client is sending exact damage rectangles we can end up with incomplete updates - the client doesn't know that the previous frame resulted in some pixel bleeding, and can't reasonably get damage right. To fix this, we'll dilate the damage region by a little bit all around. We may be dilating a little too much, but a pixel or two too far is better than being too small. The problem is easily seen with weston_simple_damage when the output is zoomed, or when running with a lower buffer scale than the output scale. The moving circle will leave trails. Signed-off-by: Derek Foreman <[email protected]> --- src/gl-renderer.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/gl-renderer.c b/src/gl-renderer.c index ae72f32..eb18931 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -1006,6 +1006,33 @@ output_rotate_damage(struct weston_output *output, go->border_damage[go->buffer_damage_index] = border_status; } +static void +region_dilate(pixman_region32_t *region, double size) +{ + pixman_box32_t *src_rects, *dest_rects; + int nrects, i; + + src_rects = pixman_region32_rectangles(region, &nrects); + dest_rects = malloc(nrects * sizeof(*dest_rects)); + if (!dest_rects) + return; + + for (i = 0; i < nrects; i++) { + dest_rects[i].x1 = src_rects[i].x1 - size; + if (dest_rects[i].x1 < 0) + dest_rects[i].x1 = 0; + dest_rects[i].x2 = src_rects[i].x2 + size; + dest_rects[i].y1 = src_rects[i].y1 - size; + if (dest_rects[i].y1 < 0) + dest_rects[i].y1 = 0; + dest_rects[i].y2 = src_rects[i].y2 + size; + } + + pixman_region32_clear(region); + pixman_region32_init_rects(region, dest_rects, nrects); + free(dest_rects); +} + /* NOTE: We now allow falling back to ARGB gl visuals when XRGB is * unavailable, so we're assuming the background has no transparency * and that everything with a blend, like drop shadows, will have something @@ -1016,7 +1043,7 @@ output_rotate_damage(struct weston_output *output, */ static void gl_renderer_repaint_output(struct weston_output *output, - pixman_region32_t *output_damage) + pixman_region32_t *output_damage_in) { struct gl_output_state *go = get_output_state(output); struct weston_compositor *compositor = output->compositor; @@ -1028,12 +1055,25 @@ gl_renderer_repaint_output(struct weston_output *output, EGLint *egl_damage, *d; pixman_box32_t *rects; #endif + pixman_region32_t output_damage; pixman_region32_t buffer_damage, total_damage; enum gl_border_status border_damage = BORDER_STATUS_CLEAN; if (use_output(output) < 0) return; + pixman_region32_init(&output_damage); + pixman_region32_copy(&output_damage, output_damage_in); + + /* When the output is scaled or zoomed a single buffer + * pixel may be spread across multiple output pixels. + * Therefore, if damage is exact in buffer space there may + * be bleeding into neighbouring output pixels. We dilate + * the damage region to compensate. + */ + if (output->zoom.active || output->current_scale > 1) + region_dilate(&output_damage, output->current_scale); + /* Calculate the viewport */ glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width, go->borders[GL_RENDERER_BORDER_BOTTOM].height, @@ -1056,7 +1096,7 @@ gl_renderer_repaint_output(struct weston_output *output, pixman_region32_t undamaged; pixman_region32_init(&undamaged); pixman_region32_subtract(&undamaged, &output->region, - output_damage); + &output_damage); gr->fan_debug = 0; repaint_views(output, &undamaged); gr->fan_debug = 1; @@ -1067,9 +1107,9 @@ gl_renderer_repaint_output(struct weston_output *output, pixman_region32_init(&buffer_damage); output_get_damage(output, &buffer_damage, &border_damage); - output_rotate_damage(output, output_damage, go->border_status); + output_rotate_damage(output, &output_damage, go->border_status); - pixman_region32_union(&total_damage, &buffer_damage, output_damage); + pixman_region32_union(&total_damage, &buffer_damage, &output_damage); border_damage |= go->border_status; repaint_views(output, &total_damage); @@ -1079,7 +1119,7 @@ gl_renderer_repaint_output(struct weston_output *output, draw_output_borders(output, border_damage); - pixman_region32_copy(&output->previous_damage, output_damage); + pixman_region32_copy(&output->previous_damage, &output_damage); wl_signal_emit(&output->frame_signal, output); #ifdef EGL_EXT_swap_buffers_with_damage @@ -1088,7 +1128,7 @@ gl_renderer_repaint_output(struct weston_output *output, weston_transformed_region(output->width, output->height, output->transform, output->current_scale, - output_damage, &buffer_damage); + &output_damage, &buffer_damage); if (output_has_borders(output)) { pixman_region32_translate(&buffer_damage, @@ -1131,6 +1171,7 @@ gl_renderer_repaint_output(struct weston_output *output, } go->border_status = BORDER_STATUS_CLEAN; + pixman_region32_fini(&output_damage); } static int -- 2.6.2 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
