[PATCH weston] gl-renderer: Dilate damage when output is zoomed or scaled

Derek Foreman derekf at osg.samsung.com
Wed Dec 2 11:46:17 PST 2015


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 <derekf at osg.samsung.com>
---
 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



More information about the wayland-devel mailing list