diff --git a/hw/kdrive/modesetting/modesetting.h b/hw/kdrive/modesetting/modesetting.h index 7ac59a6303..c3ffbc7cef 100644 --- a/hw/kdrive/modesetting/modesetting.h +++ b/hw/kdrive/modesetting/modesetting.h @@ -34,6 +34,9 @@ typedef struct _msPriv { typedef struct _msCursPriv { struct gbm_bo *bo; + /* For RandR */ + uint32_t *shadow; + int xhot; int yhot; diff --git a/hw/kdrive/modesetting/ms_cursor.c b/hw/kdrive/modesetting/ms_cursor.c index b43d03da19..08b8baff82 100644 --- a/hw/kdrive/modesetting/ms_cursor.c +++ b/hw/kdrive/modesetting/ms_cursor.c @@ -14,6 +14,91 @@ static Bool msShowCursor(ScreenPtr pScreen); +/* + * Given a screen coordinate, rotate back to a cursor source coordinate + */ +static void +KdRotateCoord(Rotation rotation, + int width, int height, + int x_dst, int y_dst, + int *x_src, int *y_src) +{ + int t; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = width - y_dst - 1; + y_dst = t; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = y_dst; + y_dst = height - t - 1; + break; + } + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + + if (x_dst < 0) { + x_dst = 0; + } + + if (y_dst < 0) { + y_dst = 0; + } + + *x_src = x_dst; + *y_src = y_dst; +} + +/* + * Given a cursor source coordinate, rotate to a screen coordinate + */ +static void +KdRotateCoordBack(Rotation rotation, + int width, int height, + int x_dst, int y_dst, + int *x_src, int *y_src) +{ + int t; + + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + + switch (rotation & 0xf) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + } + + *x_src = x_dst; + *y_src = y_dst; +} + static void msGetCursorSizes(int fd, int *w, int *h) { @@ -83,7 +168,8 @@ msLoadCursor(ScreenPtr pScreen, CursorPtr pCursor) uint32_t width = gbm_bo_get_width(pCurPriv->bo); uint32_t height = gbm_bo_get_width(pCurPriv->bo); uint32_t stride = gbm_bo_get_stride(pCurPriv->bo) / sizeof(uint32_t); - uint32_t *ram = gbm_bo_get_map(pCurPriv->bo); + uint32_t *map = gbm_bo_get_map(pCurPriv->bo); + uint32_t *ram = map; int x, y; @@ -97,7 +183,14 @@ msLoadCursor(ScreenPtr pScreen, CursorPtr pCursor) h = height; } - /* TODO: Deal with rotations */ + if (scrpriv->randr != RR_Rotate_0) { + if (!pCurPriv->shadow) { + pCurPriv->shadow = calloc(width * stride, sizeof(*ram)); + } + if (pCurPriv->shadow) { + ram = pCurPriv->shadow; + } + } if (bits->argb) { srcLine = bits->argb; @@ -157,9 +250,24 @@ msLoadCursor(ScreenPtr pScreen, CursorPtr pCursor) } } + if (scrpriv->randr != RR_Rotate_0) { + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + int x_in, y_in; + KdRotateCoord(scrpriv->randr, + width, height, + x, y, + &x_in, &y_in); + map[y * stride + x] = ram[y_in * stride + x_in]; + } + } + } + /* Save the cursor glyph hotspot */ - pCurPriv->xhot = bits->xhot; - pCurPriv->yhot = bits->yhot; + KdRotateCoordBack(scrpriv->randr, + width, height, + bits->xhot, bits->yhot, + &pCurPriv->xhot, &pCurPriv->yhot); return msShowCursor(pScreen); } @@ -218,18 +326,15 @@ msMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) int fd = gbm_device_get_fd(priv->gbm); + KdRotateCoordBack(scrpriv->randr, + pScreen->width, pScreen->height, + x, y, + &x, &y); + /* Offset the cursor position, so that the cursor hotspot looks right */ x -= pCurPriv->xhot; y -= pCurPriv->yhot; - if (x < 0) { - x = 0; - } - - if (y < 0) { - y = 0; - } - drmModeMoveCursor(fd, scrpriv->crtc_id, x, y); } @@ -342,6 +447,8 @@ msCursorFini(ScreenPtr pScreen) msScrPriv *scrpriv = screen->driver; msCursPriv *pCurPriv = &scrpriv->cursor; + free(pCurPriv->shadow); + pScreen->QueryBestSize = pCurPriv->QueryBestSize; gbm_bo_destroy(pCurPriv->bo);