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

Reply via email to