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

Kristian Høgsberg hoegsberg at gmail.com
Wed Jun 18 15:25:28 PDT 2014


On Wed, May 21, 2014 at 07:36:21PM +0100, Neil Roberts wrote:
> 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.

Could we just use pixman here?  We could also scale up the cursor image
when possible with that.

Kristian

> ---
>  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
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list