[PATCH weston] Apply output transform to the cursor while copying into a plane

Neil Roberts neil at linux.intel.com
Wed May 21 11:36:21 PDT 2014


Previously if the output had a transform then the cursor plane would
be disabled. However as we have to copy the cursor image into a buffer
with the CPU anyway it probably won't cost much extra to also apply
the transform in the process and then we can avoid disabling the
plane.

If the transform is either normal or flipped-180 then a slightly
faster path is used that still copies the lines one at a time with
memcpy. Otherwise there is a slower path which copies one pixel at a
time.

Previously the check for whether to disable the plane was only looking
at whether the output has a transform. However it should probably have
also been disabled if the surface has a transform. This patch changes
it to just look at the surface transform instead. It could be possible
to work out a relative transform and apply that so that any
combinations of transforms will work, but this patch doesn't attempt
that.
---
 src/compositor-drm.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 113 insertions(+), 7 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 7d514e4..553454d 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -958,7 +958,7 @@ drm_output_prepare_cursor_view(struct weston_output *output_base,
 
 	if (c->gbm == NULL)
 		return NULL;
-	if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
+	if (viewport->buffer.transform != WL_OUTPUT_TRANSFORM_NORMAL)
 		return NULL;
 	if (viewport->buffer.scale != output_base->current_scale)
 		return NULL;
@@ -979,6 +979,102 @@ drm_output_prepare_cursor_view(struct weston_output *output_base,
 }
 
 static void
+transform_cursor_buffer_slow(enum wl_output_transform transform,
+			     uint32_t *buf,
+			     unsigned char *s,
+			     int32_t width,
+			     int32_t height,
+			     int stride)
+{
+	int angle = transform & 3;
+	int swap_xy = transform & 1;
+	int flip_x, flip_y;
+	int buf_x_increment, buf_y_increment;
+	int s_y_increment;
+	int sx, sy;
+
+	/* Flip here means we flip the direction of the destination
+	 * iterators */
+	flip_x = (angle & 1) ^ (angle >> 1);
+	flip_y = (angle >> 1);
+
+	if (swap_xy) {
+		if (transform & 4)
+			flip_y = !flip_y;
+
+		if (flip_y) {
+			buf += (width - 1) * 64;
+			buf_x_increment = -64;
+		} else {
+			buf_x_increment = 64;
+		}
+
+		if (flip_x) {
+			buf += height - 1;
+			buf_y_increment = -1 - buf_x_increment * width;
+		} else {
+			buf_y_increment = 1 - buf_x_increment * width;
+		}
+	} else {
+		if (transform & 4)
+			flip_x = !flip_x;
+
+		if (flip_x) {
+			buf += width - 1;
+			buf_x_increment = -1;
+		} else {
+			buf_x_increment = 1;
+		}
+
+		if (flip_y) {
+			buf += (height - 1) * 64;
+			buf_y_increment = -64 - buf_x_increment * width;
+		} else {
+			buf_y_increment = 64 - buf_x_increment * width;
+		}
+	}
+
+	s_y_increment = stride - width * 4;
+
+	for (sy = 0; sy < height; sy++) {
+		for (sx = 0; sx < width; sx++) {
+			memcpy(buf, s, 4);
+			s += 4;
+			buf += buf_x_increment;
+		}
+		s += s_y_increment;
+		buf += buf_y_increment;
+	}
+}
+
+static void
+transform_cursor_buffer(enum wl_output_transform transform,
+			uint32_t *buf,
+			unsigned char *s,
+			int32_t width,
+			int32_t height,
+			int stride)
+{
+	int y;
+
+	switch (transform) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+		for (y = 0; y < height; y++)
+			memcpy(buf + y * 64, s + y * stride, width * 4);
+		break;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+		for (y = 0; y < height; y++)
+			memcpy(buf + y * 64, s + (height - 1 - y) * stride,
+			       width * 4);
+		break;
+	default:
+		transform_cursor_buffer_slow(transform,
+					     buf, s, width, height, stride);
+		break;
+	}
+}
+
+static void
 drm_output_set_cursor(struct drm_output *output)
 {
 	struct weston_view *ev = output->cursor_view;
@@ -989,7 +1085,8 @@ drm_output_set_cursor(struct drm_output *output)
 	struct gbm_bo *bo;
 	uint32_t buf[64 * 64];
 	unsigned char *s;
-	int i, x, y;
+	int x, y;
+	pixman_box32_t cursor_rect;
 
 	output->cursor_view = NULL;
 	if (ev == NULL) {
@@ -1009,9 +1106,9 @@ drm_output_set_cursor(struct drm_output *output)
 		stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
 		s = wl_shm_buffer_get_data(buffer->shm_buffer);
 		wl_shm_buffer_begin_access(buffer->shm_buffer);
-		for (i = 0; i < ev->surface->height; i++)
-			memcpy(buf + i * 64, s + i * stride,
-			       ev->surface->width * 4);
+		transform_cursor_buffer(output->base.transform,
+					buf, s, ev->surface->width,
+					ev->surface->height, stride);
 		wl_shm_buffer_end_access(buffer->shm_buffer);
 
 		if (gbm_bo_write(bo, buf, sizeof buf) < 0)
@@ -1025,8 +1122,17 @@ drm_output_set_cursor(struct drm_output *output)
 		}
 	}
 
-	x = (ev->geometry.x - output->base.x) * output->base.current_scale;
-	y = (ev->geometry.y - output->base.y) * output->base.current_scale;
+	cursor_rect.x1 = ev->geometry.x - output->base.x;
+	cursor_rect.y1 = ev->geometry.y - output->base.y;
+	cursor_rect.x2 = cursor_rect.x1 + ev->surface->width;
+	cursor_rect.y2 = cursor_rect.y1 + ev->surface->height;
+	cursor_rect = weston_transformed_rect(output->base.width,
+					      output->base.height,
+					      output->base.transform,
+					      output->base.current_scale,
+					      cursor_rect);
+	x = roundf(MIN(cursor_rect.x1, cursor_rect.x2));
+	y = roundf(MIN(cursor_rect.y1, cursor_rect.y2));
 	if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
 		if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
 			weston_log("failed to move cursor: %m\n");
-- 
1.9.0



More information about the wayland-devel mailing list