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 <stefan11111@shitposting.expert>
This commit is contained in:
stefan11111
2025-08-21 21:21:50 +03:00
committed by Enrico Weigelt
parent 6f7731c44c
commit cf092cd469
2 changed files with 186 additions and 20 deletions

View File

@@ -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)

View File

@@ -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;