From cf092cd469606319824f9221dba0f3d48e29e81c Mon Sep 17 00:00:00 2001 From: stefan11111 Date: Thu, 21 Aug 2025 21:21:50 +0300 Subject: [PATCH] modesetting: probe using the old method if SIZE_HINTS isn't available On most cards, SIZE_HINTS isn't available. Without this, most users would have to set the fallback cursor size themselves, or rely on the 64x64 default. Signed-off-by: stefan11111 --- .../video/modesetting/drmmode_display.c | 204 ++++++++++++++++-- .../video/modesetting/drmmode_display.h | 2 + 2 files changed, 186 insertions(+), 20 deletions(-) diff --git a/hw/xfree86/drivers/video/modesetting/drmmode_display.c b/hw/xfree86/drivers/video/modesetting/drmmode_display.c index be7bbc997..26137157c 100644 --- a/hw/xfree86/drivers/video/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/video/modesetting/drmmode_display.c @@ -1931,6 +1931,7 @@ drmmode_paint_cursor(struct dumb_bo *cursor_bo, int cursor_pitch, int cursor_wid } static void drmmode_hide_cursor(xf86CrtcPtr crtc); +static void drmmode_probe_cursor_size(xf86CrtcPtr crtc); /* * The load_cursor_argb_check driver hook. @@ -1945,9 +1946,17 @@ drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image) drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; modesettingPtr ms = modesettingPTR(crtc->scrn); CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen); - drmmode_cursor_rec drmmode_cursor = drmmode_crtc->cursor; int i; + if (drmmode_crtc->cursor_up) { + /* we probe the cursor so late, because we want to make sure that + the screen is fully initialized and something is already drawn on it. + Otherwise, we can't get reliable results with the probe. */ + drmmode_probe_cursor_size(crtc); + } + + drmmode_cursor_rec drmmode_cursor = drmmode_crtc->cursor; + /* Find the most compatiable size. */ for (i = 0; i < drmmode_cursor.num_dimensions; i++) { @@ -2507,6 +2516,8 @@ populate_cursor_sizes(drmmode_ptr drmmode, drmmode_crtc_private_ptr drmmode_crtc drmmode_crtc->cursor.dimensions[idx].width = size_hint.width; drmmode_crtc->cursor.dimensions[idx].height = size_hint.height; } + + drmmode_crtc->cursor_probed = TRUE; fail: drmModeFreePropertyBlob(blob); } @@ -2806,8 +2817,34 @@ drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) drmModeFreeObjectProperties(drm_props); } +static drmmode_cursor_dim_rec +drmmode_cursor_get_fallback(drmmode_crtc_private_ptr drmmode_crtc) +{ + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmmode_cursor_dim_rec fallback; + + uint64_t value = 0; + + /* We begin by using the largest supported cursor, and change it later, + when we can reliably probe for the smallest suppored cursor size */ + int ret1 = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_WIDTH, &value); + fallback.width = value; + + int ret2 = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_HEIGHT, &value); + fallback.height = value; + + /* 64x64 is the safest fallback value to use when we can't probe in any other way, + * as it is the default value that KMS uses. */ + if (ret1 || ret2) { + fallback.width = 64; + fallback.height = 64; + } + + return fallback; +} + static unsigned int -drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, drmmode_cursor_dim_rec fallback, int num) +drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) { xf86CrtcPtr crtc; drmmode_crtc_private_ptr drmmode_crtc; @@ -2838,8 +2875,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res drmmode_crtc->cursor.num_dimensions = 1; drmmode_crtc->cursor.dimensions = xnfalloc(sizeof(drmmode_cursor_dim_rec)); - drmmode_crtc->cursor.dimensions[0].width = fallback.width; - drmmode_crtc->cursor.dimensions[0].height = fallback.height; + drmmode_crtc->cursor.dimensions[0] = drmmode_cursor_get_fallback(drmmode_crtc); props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num], DRM_MODE_OBJECT_CRTC); @@ -4164,27 +4200,12 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, "Up to %d crtcs needed for screen.\n", crtcs_needed); - drmmode_cursor_dim_rec fallback; - - int ret1 = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_WIDTH, &value); - fallback.width = value; - - int ret2 = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_HEIGHT, &value); - fallback.height = value; - - /* This is the safest fallback value as - * it is the default value that KMS uses. */ - if (ret1 || ret2) { - fallback.width = 64; - fallback.height = 64; - } - xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); for (i = 0; i < mode_res->count_crtcs; i++) if (!xf86IsEntityShared(pScrn->entityList[0]) || (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i)))) - crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, fallback, i); + crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); /* All ZaphodHeads outputs provided with matching crtcs? */ if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) @@ -4652,6 +4673,149 @@ drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) #endif } +static inline void +drmmode_reset_cursor(drmmode_crtc_private_ptr drmmode_crtc) +{ + /* Mark the entire cursor buffer as dirty */ + drmmode_crtc->cursor_glyph_width = 0; + drmmode_crtc->cursor_glyph_height = 0; + drmmode_crtc->old_pitch = 0; + + /* If we had any cursor pitches for the old cursor, they are no longer valid now */ + free(drmmode_crtc->cursor_pitches); + drmmode_crtc->cursor_pitches = NULL; +} + +/* + * This is the old probe method for the minimum cursor size. + * This is only used if the SIZE_HINTS probe fails. + */ +static void drmmode_probe_cursor_size(xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + uint32_t handle = drmmode_crtc->cursor.bo->handle; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmmode_cursor_ptr drmmode_cursor = &drmmode_crtc->cursor; + int width, height, size; + int max_width, max_height; + int min_width, min_height; + + if (drmmode_crtc->cursor_probed) { + return; + } + + drmmode_crtc->cursor_probed = TRUE; + + xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, + "Probing the cursor size using the old method\n"); + + /* If we're here, we only have one size, the fallback size */ + max_width = drmmode_cursor->dimensions[0].width; + max_height = drmmode_cursor->dimensions[0].height; + + min_width = max_width; + min_height = max_height; + + /* probe square min first */ + for (size = 1; size <= max_width && + size <= max_height; size *= 2) { + int ret; + + ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + handle, size, size, 0, 0); + if (ret == 0) { + min_width = size; + min_height = size; + break; + } + } + + /* check if smaller width works with non-square */ + for (width = 1; width <= size; width *= 2) { + int ret; + + ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + handle, width, size, 0, 0); + if (ret == 0) { + min_width = width; + break; + } + } + + /* check if smaller height works with non-square */ + for (height = 1; height <= size; height *= 2) { + int ret; + + ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + handle, size, height, 0, 0); + if (ret == 0) { + min_height = height; + break; + } + } + + drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0, 0, 0); + + if (min_width == max_width && min_height == max_height) { + xf86DrvMsgVerb(crtc->scrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, + "Cursor size: %dx%d\n", + min_width, min_height); + + return; + } + + drmmode_reset_cursor(drmmode_crtc); + + /* + * We could add as many sizes as we want here. + * We want the minimum size to be here, and we need the maximum size to be here, + * because that's what we initialize the cursor image with, and we could theoretically + * get cursor glyph sizes that big. + * + * There is no problem with multiple sizes being equal here. + * We want dimensions[i] <= dimensions[i + 1] for all i, but even if + * this doesn't happen, there shouldn't be any issues. + */ + + int num_dimensions = 1; + if (min_width > min_height) { + for(int j = min_height; j <= min_width; j *= 2) { + num_dimensions++; + } + } else { + for(int j = min_width; j <= min_height; j *= 2) { + num_dimensions++; + } + + } + drmmode_cursor->num_dimensions = num_dimensions; + drmmode_cursor->dimensions = xnfrealloc(drmmode_cursor->dimensions, num_dimensions * sizeof(drmmode_cursor_dim_rec)); + + if (min_width > min_height) { + int idx = 0; + for(int j = min_height; j <= min_width; j *= 2) { + drmmode_cursor->dimensions[idx].width = min_width; + drmmode_cursor->dimensions[idx].height = j; + idx++; + } + } else { + int idx = 0; + for(int j = min_width; j <= min_height; j *= 2) { + drmmode_cursor->dimensions[idx].width = j; + drmmode_cursor->dimensions[idx].height = min_height; + idx++; + } + } + + /* maximum size */ + drmmode_cursor->dimensions[num_dimensions - 1].width = max_width; + drmmode_cursor->dimensions[num_dimensions - 1].height = max_height; + + xf86DrvMsgVerb(crtc->scrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, + "Minimum cursor size: %dx%d\n", + min_width, min_height); +} + /* create front and cursor BOs */ Bool drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) diff --git a/hw/xfree86/drivers/video/modesetting/drmmode_display.h b/hw/xfree86/drivers/video/modesetting/drmmode_display.h index 71e31b39b..9374601cf 100644 --- a/hw/xfree86/drivers/video/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/video/modesetting/drmmode_display.h @@ -252,6 +252,8 @@ typedef struct { uint32_t cursor_glyph_height; int old_pitch; + Bool cursor_probed; + int* cursor_pitches; } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;