[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