From 5e06d2b3b1f7cba514f02c8a0d25ac47db52a5fb Mon Sep 17 00:00:00 2001 From: stefan11111 Date: Sun, 4 Oct 2026 16:02:23 +0300 Subject: [PATCH] kdrive/modesetting: Implement hw cursor RandR Discovered a bug where, when Xmodesetting is started with an initially-rotated screen, the cursor position is incorectly clamped to the unrotated screen width and height. This doesn't happen when Xmodesetting is started without any rotations and then rotated with xrandr. Needs investigating Signed-off-by: stefan11111 --- hw/kdrive/modesetting/modesetting.h | 3 + hw/kdrive/modesetting/ms_cursor.c | 131 +++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 12 deletions(-) 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);