From be9589dfa2158826c392b3a151768db4668598bf Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 14:36:53 +0100 Subject: [PATCH 01/24] modesetting: Add DRMMODE_PLANE_SIZE_HINTS Will be used by upcoming commits. --- hw/xfree86/drivers/modesetting/drmmode_display.c | 1 + hw/xfree86/drivers/modesetting/drmmode_display.h | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 25ba2366d..c0dd2e78f 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2084,6 +2084,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", }, [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", }, [DRMMODE_PLANE_IN_FORMATS_ASYNC] = { .name = "IN_FORMATS_ASYNC", }, + [DRMMODE_PLANE_SIZE_HINTS] = { .name = "SIZE_HINTS" }, [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", }, [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", }, [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", }, diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 89eee103c..9100f6cd0 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -43,6 +43,7 @@ enum drmmode_plane_property { DRMMODE_PLANE_FB_ID, DRMMODE_PLANE_IN_FORMATS, DRMMODE_PLANE_IN_FORMATS_ASYNC, + DRMMODE_PLANE_SIZE_HINTS, DRMMODE_PLANE_CRTC_ID, DRMMODE_PLANE_SRC_X, DRMMODE_PLANE_SRC_Y, From 460b714691d7216a75f2a3c8eed9f18b86c98cd2 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 14:42:26 +0100 Subject: [PATCH 02/24] meson: Detect and define LIBDRM_PLANE_SIZE_HINTS --- include/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/include/meson.build b/include/meson.build index fd423c755..87e543f8a 100644 --- a/include/meson.build +++ b/include/meson.build @@ -101,6 +101,7 @@ conf_data.set('CONFIG_WSCONS', host_machine.system() in ['openbsd', 'netbsd'] ? conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found() ? '1' : false) conf_data.set('WITH_LIBDRM', libdrm_required ? '1' : false) +conf_data.set('LIBDRM_PLANE_SIZE_HINTS', libdrm_required ? libdrm_dep.version().version_compare('>= 2.4.122') : false) conf_data.set('GLAMOR_HAS_EGL_QUERY_DMABUF', epoxy_dep.found() and epoxy_dep.version().version_compare('>= 1.4.4') ? '1' : false) conf_data.set('GLAMOR_HAS_EGL_QUERY_DRIVER', From fd069213994fd5719176a7bbcc9a4565b07fc212 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 14:56:09 +0100 Subject: [PATCH 03/24] modesetting: Refactor drmmode_crtc_create_planes This switches up the for-loop into a switch statement, making it easier to handle different types of planes, not just primary ones. --- .../drivers/modesetting/drmmode_display.c | 82 +++++++++++-------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index c0dd2e78f..397b5095a 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2141,46 +2141,56 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) /* Only primary planes are important for atomic page-flipping */ type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE], props, DRMMODE_PLANE_TYPE__COUNT); - if (type != DRMMODE_PLANE_TYPE_PRIMARY) { - drmModeFreePlane(kplane); - drmModeFreeObjectProperties(props); - continue; - } - /* Check if plane is already on this CRTC */ - current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID], - props, 0); - if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) { - if (best_plane) { - drmModeFreePlane(best_kplane); - drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT); + switch (type) + { + case DRMMODE_PLANE_TYPE_PRIMARY: { + current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID], props, 0); + + if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) { + if (best_plane) { + drmModeFreePlane(best_kplane); + drmmode_prop_info_free(drmmode_crtc->props_plane, + DRMMODE_PLANE__COUNT); + drmModeFreeObjectProperties(props); + break; + } else { + best_plane = plane_id; + best_kplane = kplane; + blob_id = drmmode_prop_get_value( + &tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value( + &tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], props, 0); + drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, + DRMMODE_PLANE__COUNT, 1); + drmModeFreeObjectProperties(props); + break; + } + } + + if (!best_plane) { + best_plane = plane_id; + best_kplane = kplane; + blob_id = drmmode_prop_get_value( + &tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value( + &tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], props, 0); + drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, + DRMMODE_PLANE__COUNT, 1); + } else { + drmModeFreePlane(kplane); + } + + drmModeFreeObjectProperties(props); + break; } - best_plane = plane_id; - best_kplane = kplane; - blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], - props, 0); - async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], - props, 0); - drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, - DRMMODE_PLANE__COUNT, 1); - drmModeFreeObjectProperties(props); - break; - } - if (!best_plane) { - best_plane = plane_id; - best_kplane = kplane; - blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], - props, 0); - async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], - props, 0); - drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, - DRMMODE_PLANE__COUNT, 1); - } else { - drmModeFreePlane(kplane); + default: { + drmModeFreePlane(kplane); + drmModeFreeObjectProperties(props); + break; + } } - - drmModeFreeObjectProperties(props); } drmmode_crtc->plane_id = best_plane; From 9f1a563ee1a8b3d22e5ec16f8daa995ac590c1c1 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 14:58:06 +0100 Subject: [PATCH 04/24] modesetting: Add required structs for handling cursor dimensions --- hw/xfree86/drivers/modesetting/drmmode_display.c | 12 ++++++------ hw/xfree86/drivers/modesetting/drmmode_display.h | 12 +++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 397b5095a..cd2524c71 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -1478,7 +1478,7 @@ drmmode_set_cursor(xf86CrtcPtr crtc, int width, int height) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; - uint32_t handle = drmmode_crtc->cursor_bo->handle; + uint32_t handle = drmmode_crtc->cursor.bo->handle; CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen); int ret = -EINVAL; @@ -1535,7 +1535,7 @@ drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image) uint32_t *ptr; /* cursor should be mapped already */ - ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr); + ptr = (uint32_t *) (drmmode_crtc->cursor->bo->ptr); /* FIXME deal with rotation */ if (crtc->rotation == RR_Rotate_0) { @@ -4063,7 +4063,7 @@ static void drmmode_probe_cursor_size(xf86CrtcPtr crtc) { modesettingPtr ms = modesettingPTR(crtc->scrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - uint32_t handle = drmmode_crtc->cursor_bo->handle; + uint32_t handle = drmmode_crtc->cursor->bo->handle; drmmode_ptr drmmode = drmmode_crtc->drmmode; int width, height, size; @@ -4134,7 +4134,7 @@ drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) xf86CrtcPtr crtc = xf86_config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_crtc->cursor_bo = + drmmode_crtc->cursor->bo = dumb_bo_create(drmmode->fd, width, height, bpp); } @@ -4179,7 +4179,7 @@ drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) xf86CrtcPtr crtc = xf86_config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo); + ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor.bo); if (ret) return FALSE; } @@ -4203,7 +4203,7 @@ drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) xf86CrtcPtr crtc = xf86_config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo); + dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor.bo); drmmode_destroy_tearfree_shadow(crtc); } } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 9100f6cd0..e0736a911 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -184,12 +184,22 @@ typedef struct { uint32_t flip_seq; } drmmode_tearfree_rec, *drmmode_tearfree_ptr; +typedef struct { + uint16_t width, height; +} drmmode_cursor_dim_rec, *drmmode_cursor_dim_ptr; + +typedef struct { + uint16_t num_dimensions; + drmmode_cursor_dim_rec* dimensions; + struct dumb_bo *bo; +} drmmode_cursor_rec, *drmmode_cursor_ptr; + typedef struct { drmmode_ptr drmmode; drmModeCrtcPtr mode_crtc; uint32_t vblank_pipe; int dpms_mode; - struct dumb_bo *cursor_bo; + drmmode_cursor_rec cursor; Bool cursor_up; uint16_t lut_r[256], lut_g[256], lut_b[256]; From f4e9ce14b7ea9eea861719906ea1739f0691d931 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 16:24:21 +0100 Subject: [PATCH 05/24] modesetting: Fix up cursor size probing. modesetting has a sort of broken concept of getting the cursor dimensions since 1f41320, which causes issues on virtual machines and older AMD hardware. Our solution is to use SIZE_HINTS which is available in i915 since 2023, otherwise falling back to getting the maximum cursor size provided by the driver, if a driver wants to have a more optimal cursor size, it is more than welcome to implement SIZE_HINTS in it's DRM interface. --- hw/xfree86/drivers/modesetting/driver.c | 20 +- hw/xfree86/drivers/modesetting/driver.h | 3 - .../drivers/modesetting/drmmode_display.c | 234 ++++++++++++------ .../drivers/modesetting/drmmode_display.h | 2 + 4 files changed, 172 insertions(+), 87 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 2b34d1d9d..2bf9a39c9 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -1401,17 +1401,6 @@ PreInit(ScrnInfoPtr pScrn, int flags) ms->drmmode.sw_cursor = TRUE; } - ms->max_cursor_width = 64; - ms->max_cursor_height = 64; - ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_WIDTH, &value); - if (!ret) { - ms->max_cursor_width = value; - } - ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_HEIGHT, &value); - if (!ret) { - ms->max_cursor_height = value; - } - try_enable_glamor(pScrn); if (!ms->drmmode.glamor) { @@ -2136,10 +2125,15 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) PointPriv->spriteFuncs = &drmmode_sprite_funcs; } + /* Get the maximum cursor size. */ + drmmode_cursor_dim_rec cursor_dim = { 0 }; + if (!drmmode_get_largest_cursor(pScrn, &cursor_dim)) + return FALSE; + /* Need to extend HWcursor support to handle mask interleave */ if (!ms->drmmode.sw_cursor) - xf86_cursors_init(pScreen, ms->max_cursor_width, ms->max_cursor_height, - HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 | + xf86_cursors_init(pScreen, cursor_dim.width, cursor_dim.height, + HARDWARE_CURSOR_SOURCE_MASK_NOT_INTERLEAVED | HARDWARE_CURSOR_UPDATE_UNHIDDEN | HARDWARE_CURSOR_ARGB); diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 7f6c92551..a4c7f2ff1 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -132,9 +132,6 @@ typedef struct _modesettingRec { DamagePtr damage; Bool dirty_enabled; - uint32_t min_cursor_width, min_cursor_height; - uint32_t max_cursor_width, max_cursor_height; - Bool has_queue_sequence; Bool tried_queue_sequence; diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index cd2524c71..dbb80e2e4 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -98,6 +98,13 @@ modifiers_ptr(struct drm_format_modifier_blob *blob) return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset); } +static inline int +get_maximum_cursor_size(drmmode_cursor_rec cursor, Bool is_height) +{ + return is_height ? cursor.dimensions[cursor.num_dimensions - 1].height + : cursor.dimensions[cursor.num_dimensions - 1].width; +} + static uint32_t get_opaque_format(uint32_t format) { @@ -483,6 +490,16 @@ static void drmmode_ConvertToKMode(ScrnInfoPtr scrn, drmModeModeInfo * kmode, DisplayModePtr mode); +static void +drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode) +{ + modesettingPtr ms = modesettingPTR(crtc->scrn); + if (mode->blob_id) + drmModeDestroyPropertyBlob(ms->fd, mode->blob_id); + xorg_list_del(&mode->entry); + free(mode); +} + Bool drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y) { @@ -1528,45 +1545,51 @@ static void drmmode_hide_cursor(xf86CrtcPtr crtc); static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image) { - modesettingPtr ms = modesettingPTR(crtc->scrn); CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_cursor_rec drmmode_cursor = drmmode_crtc->cursor; int width, height, x, y, i; + int max_width, max_height; uint32_t *ptr; /* cursor should be mapped already */ - ptr = (uint32_t *) (drmmode_crtc->cursor->bo->ptr); + ptr = (uint32_t *) (drmmode_cursor.bo->ptr); - /* FIXME deal with rotation */ - if (crtc->rotation == RR_Rotate_0) { - for (width = ms->min_cursor_width; width < cursor->bits->width; ) - width *= 2; - for (height = ms->min_cursor_height; height < cursor->bits->height; ) - height *= 2; + /* We need to know what our limit is for HW cursors. */ + max_width = get_maximum_cursor_size(drmmode_cursor, FALSE); + max_height = get_maximum_cursor_size(drmmode_cursor, TRUE); - /* assume only square works for now */ - width = height = max(width, height); + /* Find the most compatiable size. */ + for (i = 0; i < drmmode_cursor.num_dimensions; i++) { + drmmode_cursor_dim_rec dimensions = drmmode_cursor.dimensions[i]; - /* if the max limits aren't square+POT we may have gone a bit over */ - width = min(width, ms->max_cursor_width); - height = min(height, ms->max_cursor_height); - } else { - width = ms->max_cursor_width; - height = ms->max_cursor_height; + if (dimensions.width >= cursor->bits->width) + break; + + if (dimensions.height >= cursor->bits->height) + break; } + /* Get the resolution of the cursor. */ + width = drmmode_cursor.dimensions[i].width; + height = drmmode_cursor.dimensions[i].height; + + /* Copy the cursor image over. */ i = 0; for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) - ptr[i++] = image[y * ms->max_cursor_width + x]; // cpu_to_le32(image[i]); + for (x = 0; x < width; x++) { + ptr[i++] = image[y * max_width + x]; + } } - /* clear the remainder for good measure */ - for (; i < ms->max_cursor_width * ms->max_cursor_height; i++) + + /* Clear the remainder for good measure. */ + for (; i < max_width * max_height; i++) ptr[i++] = 0; if (drmmode_crtc->cursor_up) return drmmode_set_cursor(crtc, width, height); - return TRUE; + else + return TRUE; } static void @@ -1940,6 +1963,15 @@ drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap, void *data) static void drmmode_crtc_destroy(xf86CrtcPtr crtc) { + drmmode_mode_ptr iterator, next; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + free(drmmode_crtc->cursor.dimensions); + + drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT); + xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) { + drm_mode_destroy(crtc, iterator); + } } static const xf86CrtcFuncsRec drmmode_crtc_funcs = { @@ -2052,6 +2084,47 @@ populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane, return TRUE; } +#ifdef LIBDRM_PLANE_SIZE_HINTS +static void +populate_cursor_sizes(drmmode_ptr drmmode, drmmode_crtc_private_ptr drmmode_crtc, int size_hints_blob) +{ + drmModePropertyBlobRes *blob; + + if (!drmmode_crtc) + return; + + if (!size_hints_blob) + return; + + blob = drmModeGetPropertyBlob(drmmode->fd, size_hints_blob); + + if (!blob) + return; + + if (!blob->length) + goto fail; + + const struct drm_plane_size_hint *size_hints = blob->data; + size_t size_hints_len = blob->length / sizeof(size_hints[0]); + + if (!size_hints_len) + goto fail; + + drmmode_crtc->cursor.num_dimensions = size_hints_len; + drmmode_crtc->cursor.dimensions = xnfrealloc(drmmode_crtc->cursor.dimensions, size_hints_len * sizeof(drmmode_cursor_dim_rec)); + + for (int idx = 0; idx < size_hints_len; idx++) + { + struct drm_plane_size_hint size_hint = size_hints[idx]; + + drmmode_crtc->cursor.dimensions[idx].width = size_hint.width; + drmmode_crtc->cursor.dimensions[idx].height = size_hint.height; + } +fail: + drmModeFreePropertyBlob(blob); +} +#endif + static void drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) { @@ -2185,6 +2258,17 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) break; } +#ifdef LIBDRM_PLANE_SIZE_HINTS + case DRMMODE_PLANE_TYPE_CURSOR: { + int size_hint = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_SIZE_HINTS], props, 0); + populate_cursor_sizes(drmmode, drmmode_crtc, size_hint); + + drmModeFreePlane(kplane); + drmModeFreeObjectProperties(props); + break; + } +#endif + default: { drmModeFreePlane(kplane); drmModeFreeObjectProperties(props); @@ -2266,7 +2350,7 @@ drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) } static unsigned int -drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) +drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, drmmode_cursor_dim_rec fallback, int num) { xf86CrtcPtr crtc; drmmode_crtc_private_ptr drmmode_crtc; @@ -2293,6 +2377,14 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res xorg_list_init(&drmmode_crtc->tearfree.dri_flip_list); drmmode_crtc->next_msc = UINT64_MAX; + /* Setup the fallback cursor immediately. */ + 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; + /* */ + props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num], DRM_MODE_OBJECT_CRTC); if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props, @@ -3594,12 +3686,28 @@ 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); + /* This is the safest fallback value. */ + drmmode_cursor_dim_rec fallback = { + .width = 64, + .height = 64, + }; + + ret = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_WIDTH, &value); + if (!ret) { + fallback.width = value; + } + + ret = drmGetCap(drmmode->fd, DRM_CAP_CURSOR_HEIGHT, &value); + if (!ret) { + fallback.height = value; + } + 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, i); + crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, fallback, i); /* All ZaphodHeads outputs provided with matching crtcs? */ if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) @@ -4059,53 +4167,37 @@ drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) #endif } -static void drmmode_probe_cursor_size(xf86CrtcPtr crtc) +Bool +drmmode_get_largest_cursor(ScrnInfoPtr pScrn, drmmode_cursor_dim_ptr cursor_lim) { - modesettingPtr ms = modesettingPTR(crtc->scrn); - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - uint32_t handle = drmmode_crtc->cursor->bo->handle; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - int width, height, size; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int max_width = 0, max_height = 0, i; - ms->min_cursor_width = ms->max_cursor_width; - ms->min_cursor_height = ms->max_cursor_height; + if (!cursor_lim) + return FALSE; - /* probe square min first */ - for (size = 1; size <= ms->max_cursor_width && - size <= ms->max_cursor_height; size *= 2) { - int ret; + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_cursor_rec cursor = drmmode_crtc->cursor; - ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - handle, size, size, 0, 0); - if (ret == 0) - break; - } + /* Get the largest cursor available. */ + drmmode_cursor_dim_rec largest = cursor.dimensions[cursor.num_dimensions - 1]; - /* check if smaller width works with non-square */ - for (width = 1; width <= size; width *= 2) { - int ret; + int width = largest.width; + int height = largest.height; - ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - handle, width, size, 0, 0); - if (ret == 0) { - ms->min_cursor_width = width; - break; + /* Future work: + * - We should only let sizes that all CRTCs support. */ + if (width > max_width && height > max_height) { + max_width = width; + max_height = height; } } - /* 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) { - ms->min_cursor_height = height; - break; - } - } - - drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0, 0, 0); + cursor_lim->width = max_width; + cursor_lim->height = max_height; + return TRUE; } /* create front and cursor BOs */ @@ -4127,23 +4219,23 @@ drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) return FALSE; pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp; - width = ms->max_cursor_width; - height = ms->max_cursor_height; bpp = 32; for (i = 0; i < xf86_config->num_crtc; i++) { xf86CrtcPtr crtc = xf86_config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_cursor_rec cursor = drmmode_crtc->cursor; - drmmode_crtc->cursor->bo = - dumb_bo_create(drmmode->fd, width, height, bpp); - } + /* If we don't have any dimensions then + * something has gone terribly wrong. */ + assert(cursor.num_dimensions); - drmmode_probe_cursor_size(xf86_config->crtc[0]); + /* Use the maximum available size. */ + width = get_maximum_cursor_size(cursor, FALSE); + height = get_maximum_cursor_size(cursor, TRUE); - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG, - "Supported cursor sizes %dx%d -> %dx%d\n", - ms->min_cursor_width, ms->min_cursor_height, - ms->max_cursor_width, ms->max_cursor_height); + drmmode_crtc->cursor.bo = + dumb_bo_create(drmmode->fd, width, height, bpp); + } return TRUE; } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index e0736a911..beb97db32 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -335,6 +335,8 @@ extern void drmmode_update_kms_state(drmmode_ptr drmmode); extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode); extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode); +Bool drmmode_get_largest_cursor(ScrnInfoPtr pScrn, drmmode_cursor_dim_ptr cursor_lim); + Bool drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode); void *drmmode_map_front_bo(drmmode_ptr drmmode); Bool drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode); From f535f04bb16db2be813b08dc3866e17dca2a8dd5 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Fri, 19 Dec 2025 16:27:33 +0100 Subject: [PATCH 06/24] modesetting: Use xnfcalloc instead of calloc Prevents possible memory allocation failure explosions. --- hw/xfree86/drivers/modesetting/drmmode_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index dbb80e2e4..6279eb6bb 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2280,15 +2280,15 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) drmmode_crtc->plane_id = best_plane; if (best_kplane) { drmmode_crtc->num_formats = best_kplane->count_formats; - drmmode_crtc->formats = calloc(best_kplane->count_formats, - sizeof(drmmode_format_rec)); + drmmode_crtc->formats = xnfcalloc(best_kplane->count_formats, + sizeof(drmmode_format_rec)); if (!populate_format_modifiers(crtc, best_kplane, drmmode_crtc->formats, blob_id)) { for (i = 0; i < best_kplane->count_formats; i++) drmmode_crtc->formats[i].format = best_kplane->formats[i]; } else { - drmmode_crtc->formats_async = calloc(best_kplane->count_formats, - sizeof(drmmode_format_rec)); + drmmode_crtc->formats_async = xnfcalloc(best_kplane->count_formats, + sizeof(drmmode_format_rec)); if (!populate_format_modifiers(crtc, best_kplane, drmmode_crtc->formats_async, async_blob_id)) { free(drmmode_crtc->formats_async); From 99e208d7fb7efdb46f5d6ef9a08f231d4de833e7 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Sat, 20 Dec 2025 12:31:53 +0100 Subject: [PATCH 07/24] mi: miscrinit: Avoid breaking CloseScreen() chain Breaking CloseScreen() chain may cause resources leak. --- mi/miscrinit.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/mi/miscrinit.c b/mi/miscrinit.c index 8165d0f38..0e4970c7e 100644 --- a/mi/miscrinit.c +++ b/mi/miscrinit.c @@ -60,6 +60,17 @@ typedef struct { int ysize; } miScreenInitParmsRec, *miScreenInitParmsPtr; +/* per-screen private data */ +static DevPrivateKeyRec miScreenPrivKeyRec; + +#define miScreenPrivKey (&miScreenPrivKeyRec) + +typedef struct { + CloseScreenProcPtr CloseScreen; +} miScreenRec, *miScreenPtr; + +#define miGetScreenPriv(s) ((miScreenPtr)(dixLookupPrivate(&(s)->devPrivates, miScreenPrivKey))) + #define DEFAULTZEROLINEBIAS (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5) /* this plugs into pScreen->ModifyPixmapHeader */ @@ -126,7 +137,18 @@ miModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth, static Bool miCloseScreen(ScreenPtr pScreen) { - return ((*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate)); + miScreenPtr pScreenPriv = miGetScreenPriv(pScreen); + + ((*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate)); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + + free(pScreenPriv); + + if (pScreen->CloseScreen) + return (*pScreen->CloseScreen) (pScreen); + + return TRUE; } static Bool @@ -235,6 +257,17 @@ miScreenInit(ScreenPtr pScreen, void *pbits, /* pointer to screen bits */ VisualRec * visuals /* supported visuals */ ) { + miScreenPtr pScreenPriv; + + if (!dixRegisterPrivateKey(&miScreenPrivKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + pScreenPriv = calloc(1, sizeof(miScreenRec)); + if (!pScreenPriv) + return FALSE; + + dixSetPrivate(&pScreen->devPrivates, miScreenPrivKey, pScreenPriv); + pScreen->width = xsize; pScreen->height = ysize; pScreen->mmWidth = (xsize * 254 + dpix * 5) / (dpix * 10); @@ -259,6 +292,7 @@ miScreenInit(ScreenPtr pScreen, void *pbits, /* pointer to screen bits */ #ifdef MITSHM ShmRegisterFbFuncs(pScreen); #endif + pScreenPriv->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = miCloseScreen; } /* else CloseScreen */ From 94e131911b40d019557d9d2b4a6c1d6a0708a9e2 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Sat, 20 Dec 2025 12:33:35 +0100 Subject: [PATCH 08/24] modesetting: Import front bo earlier The early dirtyfb check would use front bo's fb_id. --- hw/xfree86/drivers/modesetting/drmmode_display.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 6279eb6bb..7eefd40e0 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -506,7 +506,6 @@ drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y) drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree; - int ret; *fb_id = 0; @@ -536,16 +535,6 @@ drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y) *y = crtc->y; } - if (*fb_id == 0) { - ret = drmmode_bo_import(drmmode, &drmmode->front_bo, - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb %d\n", ret); - return FALSE; - } - *fb_id = drmmode->fb_id; - } - return TRUE; } @@ -4217,6 +4206,10 @@ drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode) if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp)) return FALSE; + + if (drmmode_bo_import(drmmode, &drmmode->front_bo, &drmmode->fb_id) < 0) + return FALSE; + pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp; bpp = 32; From 540a3b6aaf5dbe509f9dc64fa77f307869c345bd Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 11:27:51 +0100 Subject: [PATCH 09/24] dri3: Free formats on CloseScreen. Direct leak of 1040 byte(s) in 1 object(s) allocated from: 0x769755818bf0 in calloc /usr/src/debug/gcc/gcc/libsanitizer/lsan/lsan_interceptors.cpp:91 0x635b83ec11c4 in cache_formats_and_modifiers ../spaghetti/dri3/dri3_screen.c:186 0x635b83ec11c4 in dri3_get_supported_modifiers ../spaghetti/dri3/dri3_screen.c:233 0x635b83ec0512 in proc_dri3_get_supported_modifiers ../spaghetti/dri3/dri3_request.c:395 --- dri3/dri3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dri3/dri3.c b/dri3/dri3.c index 2675b44ff..a8897697a 100644 --- a/dri3/dri3.c +++ b/dri3/dri3.c @@ -36,6 +36,9 @@ dri3_close_screen(ScreenPtr screen) unwrap(screen_priv, screen, CloseScreen); + if (screen_priv->formats) + free(screen_priv->formats); + free(screen_priv); return (*screen->CloseScreen) (screen); } From c1233028c79f6988dab3763123b00fa2ca5b90b2 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 12:53:58 +0100 Subject: [PATCH 10/24] dix,exa,glx: Add allocation failure guards. --- dix/dixfonts.c | 5 ++--- exa/exa_mixed.c | 3 +++ glx/glxscreens.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dix/dixfonts.c b/dix/dixfonts.c index 00ab157a7..56c804a47 100644 --- a/dix/dixfonts.c +++ b/dix/dixfonts.c @@ -693,9 +693,8 @@ doListFontsAndAliases(ClientPtr client, LFclosurePtr c) c->saved = c->current; c->haveSaved = TRUE; free(c->savedName); - c->savedName = malloc(namelen + 1); - if (c->savedName) - memcpy(c->savedName, name, namelen + 1); + c->savedName = XNFalloc(namelen + 1); + memcpy(c->savedName, name, namelen + 1); c->savedNameLen = namelen; aliascount = 20; } diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c index 7138f9b30..d9c2b6b10 100644 --- a/exa/exa_mixed.c +++ b/exa/exa_mixed.c @@ -98,6 +98,9 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, if (w == 1 && h == 1) { pExaPixmap->sys_ptr = malloc(paddedWidth); + if (!pExaPixmap->sys_ptr) + return NullPixmap; + /* Set up damage tracking */ pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL, DamageReportNonEmpty, TRUE, diff --git a/glx/glxscreens.c b/glx/glxscreens.c index ef969fcd6..9f04ecd81 100644 --- a/glx/glxscreens.c +++ b/glx/glxscreens.c @@ -339,7 +339,7 @@ __glXScreenInit(__GLXscreen * pGlxScreen, ScreenPtr pScreen) pGlxScreen->numFBConfigs = i; pGlxScreen->visuals = - calloc(pGlxScreen->numFBConfigs, sizeof(__GLXconfig *)); + XNFcallocarray(pGlxScreen->numFBConfigs, sizeof(__GLXconfig *)); /* First, try to choose featureful FBconfigs for the existing X visuals. * Note that if multiple X visuals end up with the same FBconfig being From a90ea37c8fdfc66f15925c0fa60a4b0372209916 Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Mon, 22 Dec 2025 12:54:10 +0100 Subject: [PATCH 11/24] os: make FormatInt64() handle LONG_MIN correctly When compiling with gcc 15.2.0 using -O3 -m64 on Solaris SPARC & x64, we'd get a test failure of: Assertion failed: strcmp(logmsg, expected) == 0, file ../test/signal-logging.c, line 339, function logging_format because 'num *= 1' produced a value that was out of the range of the int64_t it was being stored in. (Compiling with -O2 worked fine with the same compiler/configuration/platform though.) --- os/fmt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/os/fmt.c b/os/fmt.c index c5c61bdba..7bda7014a 100644 --- a/os/fmt.c +++ b/os/fmt.c @@ -16,12 +16,14 @@ void FormatInt64(int64_t num, char *string) { + uint64_t unum = num; + if (num < 0) { string[0] = '-'; - num *= -1; + unum = num * -1; string++; } - FormatUInt64(num, string); + FormatUInt64(unum, string); } /* Format a number into a string in a signal safe manner. The string should be From 612c5fe72d2b430130c0d0404d79bd1c4611ea39 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 22 Dec 2025 13:12:58 +0100 Subject: [PATCH 12/24] exa: Fix crash after CloseScreen() After moving CloseScreen() before dixFreeScreenSpecificPrivates(), we need to make sure private keys available after CloseScreen(). --- exa/exa.c | 16 ++++++---------- exa/exa_priv.h | 2 +- hw/xfree86/exa/examodule.c | 4 +++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/exa/exa.c b/exa/exa.c index f62d3c45e..0717fc042 100644 --- a/exa/exa.c +++ b/exa/exa.c @@ -773,8 +773,6 @@ exaCloseScreen(ScreenPtr pScreen) unwrap(pExaScr, ps, Triangles); unwrap(pExaScr, ps, AddTraps); - free(pExaScr); - return (*pScreen->CloseScreen) (pScreen); } @@ -876,27 +874,25 @@ exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo) ps = GetPictureScreenIfSet(pScreen); - if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) { - LogMessage(X_WARNING, "EXA(%d): Failed to register screen private\n", + if (!dixRegisterPrivateKey(&exaScreenPrivateKeyRec, PRIVATE_SCREEN, sizeof(ExaScreenPrivRec))) { + LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", pScreen->myNum); return FALSE; } - pExaScr = calloc(1, sizeof(ExaScreenPrivRec)); + pExaScr = ExaGetScreenPriv(pScreen); if (!pExaScr) { - LogMessage(X_WARNING, "EXA(%d): Failed to allocate screen private\n", - pScreen->myNum); return FALSE; } pExaScr->info = pScreenInfo; - - dixSetPrivate(&pScreen->devPrivates, exaScreenPrivateKey, pExaScr); - pExaScr->migration = ExaMigrationAlways; exaDDXDriverInit(pScreen); + /* private re-allocated */ + pExaScr = ExaGetScreenPriv(pScreen); + if (!dixRegisterScreenSpecificPrivateKey (pScreen, &pExaScr->gcPrivateKeyRec, PRIVATE_GC, sizeof(ExaGCPrivRec))) { LogMessage(X_WARNING, "EXA(%d): Failed to allocate GC private\n", diff --git a/exa/exa_priv.h b/exa/exa_priv.h index 4da0a6683..befaef3e9 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -218,7 +218,7 @@ extern DevPrivateKeyRec exaPixmapPrivateKeyRec; #define exaScreenPrivateKey (&exaScreenPrivateKeyRec) -#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivate(&(s)->devPrivates, exaScreenPrivateKey)) +#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivateAddr(&(s)->devPrivates, exaScreenPrivateKey)) #define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s) #define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixGetPrivateAddr(&(gc)->devPrivates, &ExaGetScreenPriv(gc->pScreen)->gcPrivateKeyRec)) diff --git a/hw/xfree86/exa/examodule.c b/hw/xfree86/exa/examodule.c index 0b0bf8118..419f4f19f 100644 --- a/hw/xfree86/exa/examodule.c +++ b/hw/xfree86/exa/examodule.c @@ -110,7 +110,6 @@ exaXorgEnableDisableFBAccess(ScrnInfoPtr pScrn, Bool enable) void exaDDXDriverInit(ScreenPtr pScreen) { - ExaScreenPriv(pScreen); ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); ExaXorgScreenPrivPtr pScreenPriv; @@ -125,6 +124,9 @@ exaDDXDriverInit(ScreenPtr pScreen) memcpy(pScreenPriv->options, EXAOptions, sizeof(EXAOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pScreenPriv->options); + /* private re-allocated */ + ExaScreenPriv(pScreen); + if (pExaScr->info->flags & EXA_OFFSCREEN_PIXMAPS) { if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && pExaScr->info->offScreenBase < pExaScr->info->memorySize) { From d1aad7da2fc224919ba67c4ca34060adf4fec749 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 13:14:32 +0100 Subject: [PATCH 13/24] modesetting: Add warning in drmmode_output_create_resources. We _shouldn't_ be reallocating the property count as this would leak memory, use BUG_WARN to log if such a scenario occurs. --- hw/xfree86/drivers/modesetting/drmmode_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 7eefd40e0..18863dd08 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2812,6 +2812,8 @@ drmmode_output_create_resources(xf86OutputPtr output) drmModePropertyPtr drmmode_prop; int i, j, err; + BUG_RETURN(drmmode_output->props != NULL); + drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); if (!drmmode_output->props) From 14efe7222f3484e44f4c28c6dd9301aac491349f Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 13:15:14 +0100 Subject: [PATCH 14/24] modesetting: Always finalize the cursor. We should also be doing this with a software cursor. --- hw/xfree86/drivers/modesetting/driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 2bf9a39c9..3321b55f3 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -2356,8 +2356,7 @@ CloseScreen(ScreenPtr pScreen) ms->drmmode.shadow_fb2 = NULL; } - if (!ms->drmmode.sw_cursor) - xf86_cursors_fini(pScreen); + xf86_cursors_fini(pScreen); drmmode_uevent_fini(pScrn, &ms->drmmode); From f42d109864d3d06d67b9b79326506acd57e955d6 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Mon, 22 Dec 2025 13:19:22 +0100 Subject: [PATCH 15/24] dri2: Fix sw cursor rendering issue When reporting damage, the misprite swcursor will try to remove cursor by restoring the under cursor area. This will override the previous draw, so we need to move it before the rendering. --- hw/xfree86/drivers/modesetting/dri2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/dri2.c b/hw/xfree86/drivers/modesetting/dri2.c index af7db7ddc..5521c2212 100644 --- a/hw/xfree86/drivers/modesetting/dri2.c +++ b/hw/xfree86/drivers/modesetting/dri2.c @@ -619,8 +619,6 @@ ms_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, *front_pix = *back_pix; *back_pix = tmp_pix; - ms->glamor.egl_exchange_buffers(front_priv->pixmap, back_priv->pixmap); - /* Post damage on the front buffer so that listeners, such * as DisplayLink know take a copy and shove it over the USB. */ @@ -628,7 +626,11 @@ ms_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, region.extents.x2 = front_priv->pixmap->drawable.width; region.extents.y2 = front_priv->pixmap->drawable.height; region.data = NULL; + DamageRegionAppend(&front_priv->pixmap->drawable, ®ion); + + ms->glamor.egl_exchange_buffers(front_priv->pixmap, back_priv->pixmap); + DamageRegionProcessPending(&front_priv->pixmap->drawable); } From 25b9aa2f1b673f35aeb77c2f722edb9b9d4073c1 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 14:57:20 +0100 Subject: [PATCH 16/24] modesetting: Print error message for flip queue retry This should be more useful for debugging. --- hw/xfree86/drivers/modesetting/pageflip.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/pageflip.c b/hw/xfree86/drivers/modesetting/pageflip.c index 9eaeb2dbd..e28efdb74 100644 --- a/hw/xfree86/drivers/modesetting/pageflip.c +++ b/hw/xfree86/drivers/modesetting/pageflip.c @@ -185,8 +185,9 @@ do_queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc, uint32_t flags, { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree; + int ret; - while (drmmode_crtc_flip(crtc, fb_id, x, y, flags, (void *)(long)seq)) { + while ((ret = drmmode_crtc_flip(crtc, fb_id, x, y, flags, (void *)(long)seq))) { /* We may have failed because the event queue was full. Flush it * and retry. If there was nothing to flush, then we failed for * some other reason and should just return an error. @@ -202,7 +203,7 @@ do_queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc, uint32_t flags, } /* We flushed some events, so try again. */ - xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, "flip queue retry\n"); + xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, "flip queue retry (%s)\n", strerror(ret)); } return FALSE; From bed18ac8a8b55467f5b56cd320f98c04d399feee Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 22 Dec 2025 17:50:59 +0100 Subject: [PATCH 17/24] xf86: Accept platform devices with efidrm/vesadrm DRM kernel drivers Add a workaround to accept devices of the kernel's efidrm driver. Makes Xorg work on pre-configured displays with UEFI and the DRM graphics stack. Review of the efidrm driver happens at [1]. v2: Use a allowlist array for matching supported kernel devices. - notbabaisyou Co-authored-by: notbabaisyou --- hw/xfree86/common/xf86platformBus.c | 36 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c index 2962c8b21..0e055b3d0 100644 --- a/hw/xfree86/common/xf86platformBus.c +++ b/hw/xfree86/common/xf86platformBus.c @@ -60,8 +60,32 @@ int platformSlotClaimed; int xf86_num_platform_devices; +/** + * These kernel devices should be allowed + * to attach to modesetting by default. + */ +static const char* DEVICE_ALLOWLIST[] = +{ + "hyperv_drm", + "simpledrm", + "vesadrm", + "efidrm", + "ofdrm" +}; + struct xf86_platform_device *xf86_platform_devices; +static inline +Bool xf86_is_device_allowed(char* driver) +{ + const int size = sizeof(DEVICE_ALLOWLIST) / sizeof(DEVICE_ALLOWLIST[0]); + for (int idx = 0; idx < size; idx++) + if (strcmp(driver, DEVICE_ALLOWLIST[idx]) == 0) + return TRUE; + + return FALSE; +} + int xf86_add_platform_device(struct OdevAttributes *attribs, Bool unowned) { @@ -579,16 +603,8 @@ xf86platformProbeDev(DriverPtr drvp) /* for non-seat0 servers assume first device is the master */ if (ServerIsNotSeat0()) { break; - } else { - /* Accept the device if the driver is hyperv_drm */ - if (strcmp(xf86_platform_devices[j].attribs->driver, "hyperv_drm") == 0) - break; - /* Accept the device if the driver is ofdrm */ - if (strcmp(xf86_platform_devices[j].attribs->driver, "ofdrm") == 0) - break; - /* Accept the device if the driver is simpledrm */ - if (strcmp(xf86_platform_devices[j].attribs->driver, "simpledrm") == 0) - break; + } else if (xf86_is_device_allowed(xf86_platform_devices[j].attribs->driver)) { + break; } if (xf86IsPrimaryPlatform(&xf86_platform_devices[j])) From c074e779624e13968d244a70ed9e647700c47e41 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 19:13:33 +0100 Subject: [PATCH 18/24] modesetting: Re-shuffle _modesettingRec around. I want to squeeze in a new value called `universal_planes`, for this I want to reduce the padding in the struct. Also removes unused SaveGeneration variable. --- hw/xfree86/drivers/modesetting/driver.c | 1 - hw/xfree86/drivers/modesetting/driver.h | 12 +++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 3321b55f3..f1960c9f1 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -1330,7 +1330,6 @@ PreInit(ScrnInfoPtr pScrn, int flags) pEnt = xf86GetEntityInfo(pScrn->entityList[0]); ms = modesettingPTR(pScrn); - ms->SaveGeneration = -1; ms->pEnt = pEnt; ms->drmmode.is_secondary = FALSE; pScrn->displayWidth = 640; /* default it */ diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index a4c7f2ff1..27d5a7296 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -102,16 +102,14 @@ struct ms_drm_queue { typedef struct _modesettingRec { int fd; - Bool fd_passed; - int Chipset; - EntityInfoPtr pEnt; + Bool fd_passed; Bool noAccel; + + EntityInfoPtr pEnt; CloseScreenProcPtr CloseScreen; CreateWindowProcPtr CreateWindow; - unsigned int SaveGeneration; - CreateScreenResourcesProcPtr createScreenResources; ScreenBlockHandlerProcPtr BlockHandler; miPointerSpriteFuncPtr SpriteFuncs; @@ -126,7 +124,9 @@ typedef struct _modesettingRec { * @{ */ Bool atomic_modeset_capable; + Bool universal_planes; Bool pending_modeset; + Bool kms_has_modifiers; /** @} */ DamagePtr damage; @@ -135,8 +135,6 @@ typedef struct _modesettingRec { Bool has_queue_sequence; Bool tried_queue_sequence; - Bool kms_has_modifiers; - /* VRR support */ Bool vrr_support; WindowPtr flip_window; From 275fb673ca416c3685b117f34a5c76b782058367 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 22 Dec 2025 19:19:25 +0100 Subject: [PATCH 19/24] modesetting: Track and use universal plane support This should fix up DRM leasing on modesetting, we also now only set DRM_CLIENT_CAP_UNIVERSAL_PLANES once instead of multiple times per-CRTC and during TearFree setup. --- hw/xfree86/drivers/modesetting/driver.c | 11 +++++++++-- hw/xfree86/drivers/modesetting/drmmode_display.c | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index f1960c9f1..0e45901cb 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -1466,6 +1466,14 @@ PreInit(ScrnInfoPtr pScrn, int flags) ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 0); ms->atomic_modeset_capable = (ret == 0); + /* + * Universal planes are implied by atomic modeset. However, if atomic modeset + * is disabled, universal planes are still useful for us to understand what + * modifiers the primary plane can support (see drmmode_crtc_create_planes()) + */ + ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + ms->universal_planes = (ret == 0); + /* TearFree requires glamor and, if PageFlip is enabled, universal planes */ if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_TEARFREE, TRUE)) { if (pScrn->is_gpu) { @@ -1473,8 +1481,7 @@ PreInit(ScrnInfoPtr pScrn, int flags) "TearFree cannot synchronize PRIME; use 'PRIME Synchronization' instead\n"); } else if (ms->drmmode.glamor) { /* Atomic modesetting implicitly enables universal planes */ - if (!ms->drmmode.pageflip || - !drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { + if (!ms->drmmode.pageflip || ms->universal_planes) { ms->drmmode.tearfree_enable = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TearFree: enabled\n"); } else { diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 18863dd08..f0a2bf50b 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2165,7 +2165,6 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) return; } - drmSetClientCap(drmmode->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); kplane_res = drmModeGetPlaneResources(drmmode->fd); if (!kplane_res) { xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR, @@ -3567,6 +3566,9 @@ drmmode_create_lease(RRLeasePtr lease, int *fd) nobjects = ncrtc + noutput; + if (ms->universal_planes) + nobjects += ncrtc; /* account for planes as well */ + if (nobjects == 0) return BadValue; @@ -3589,6 +3591,9 @@ drmmode_create_lease(RRLeasePtr lease, int *fd) drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; objects[i++] = drmmode_crtc->mode_crtc->crtc_id; + + if (ms->universal_planes) + objects[i++] = drmmode_crtc->plane_id; } /* Add connector ids */ From 43e982a4155cfb248ecf43957af7f0aa889989b1 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Tue, 30 Dec 2025 12:36:32 +0100 Subject: [PATCH 20/24] modesetting: Guard gbm_bo_unmap behind GLAMOR_HAS_GBM_MAP --- hw/xfree86/drivers/modesetting/drmmode_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index f0a2bf50b..0b3dd4081 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -3379,6 +3379,7 @@ drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo) if (!drmmode->glamor) return TRUE; +#ifdef GLAMOR_HAS_GBM_MAP /* Calling egl_create_textured_pixmap_from_gbm_bo in GLAMOR will * destroy the GBM BO, we need to unmap pointers ahead of time. */ if (bo->gbm && bo->gbm_ptr) { @@ -3386,6 +3387,7 @@ drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo) bo->gbm_ptr = NULL; bo->gbm_map_data = NULL; } +#endif if (!ms->glamor.egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm, bo->used_modifiers)) { From 4792c01fe1b300e6969f30aad0e4a29371a595f5 Mon Sep 17 00:00:00 2001 From: Alexander Melnyk Date: Tue, 30 Dec 2025 16:31:31 +0100 Subject: [PATCH 21/24] xkb: Fix locked group indicator desync on multi-HID keyboards When a group indicator is defined, e.g.: indicator "Scroll Lock" { groups = Group2; } the logical and physical indicator state may desync if the keyboard exposes multiple HID interfaces. This is caused by XkbPushLockedStateToSlaves only pushing locked_mods to the slave devices. Pushing locked_group along with locked_mods resolves the issue. The issue is not observed with API calls because a different code path is taken (avoiding XkbPushLockedStateToSlaves altogether). --- xkb/xkbActions.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c index aad475e6f..3eb232da6 100644 --- a/xkb/xkbActions.c +++ b/xkb/xkbActions.c @@ -1239,6 +1239,8 @@ XkbPushLockedStateToSlaves(DeviceIntPtr master, int evtype, int key) dev->key->xkbInfo->state.locked_mods = master->key->xkbInfo->state.locked_mods; + dev->key->xkbInfo->state.locked_group = + master->key->xkbInfo->state.locked_group; _XkbApplyState(dev, genStateNotify, evtype, key); } From a8f7197010adb0aff9e44d5107e52f1a9300c8c8 Mon Sep 17 00:00:00 2001 From: Peng Jin Date: Tue, 30 Dec 2025 16:42:07 +0100 Subject: [PATCH 22/24] xfree86: Support Moore Threads GPU --- hw/xfree86/common/xf86pciBus.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/xfree86/common/xf86pciBus.c b/hw/xfree86/common/xf86pciBus.c index e42d1cd39..18b60e6bf 100644 --- a/hw/xfree86/common/xf86pciBus.c +++ b/hw/xfree86/common/xf86pciBus.c @@ -1190,6 +1190,9 @@ xf86VideoPtrToDriverList(struct pci_device *dev, XF86MatchedDrivers *md) case 0x102b: driverList[0] = "mga"; break; + case 0x1ed5: + driverList[0] = "mtgpu"; + break; case 0x10c8: driverList[0] = "neomagic"; break; From 8ac8720fbefac5a6e530c419ae52f300d17a66b3 Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Tue, 30 Dec 2025 16:47:27 +0100 Subject: [PATCH 23/24] modesetting: Fix tab usage in ms_present_unflip --- hw/xfree86/drivers/modesetting/present.c | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index a127fb084..e9484c478 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -460,25 +460,25 @@ ms_present_unflip(ScreenPtr screen, uint64_t event_id) for (i = 0; i < config->num_crtc; i++) { xf86CrtcPtr crtc = config->crtc[i]; - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - - if (!crtc->enabled) - continue; - - /* info->drmmode.fb_id still points to the FB for the last flipped BO. - * Clear it, drmmode_set_mode_major will re-create it - */ - if (drmmode_crtc->drmmode->fb_id) { - drmModeRmFB(drmmode_crtc->drmmode->fd, - drmmode_crtc->drmmode->fb_id); - drmmode_crtc->drmmode->fb_id = 0; - } - - if (drmmode_crtc->dpms_mode == DPMSModeOn) - crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, - crtc->x, crtc->y); - else - drmmode_crtc->need_modeset = TRUE; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!crtc->enabled) + continue; + + /* info->drmmode.fb_id still points to the FB for the last flipped BO. + * Clear it, drmmode_set_mode_major will re-create it + */ + if (drmmode_crtc->drmmode->fb_id) { + drmModeRmFB(drmmode_crtc->drmmode->fd, + drmmode_crtc->drmmode->fb_id); + drmmode_crtc->drmmode->fb_id = 0; + } + + if (drmmode_crtc->dpms_mode == DPMSModeOn) + crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + else + drmmode_crtc->need_modeset = TRUE; } present_event_notify(event_id, 0, 0); From ddaaa7f22f03dbb2c749342cfc77b8f8417e88bd Mon Sep 17 00:00:00 2001 From: hongao Date: Tue, 30 Dec 2025 16:51:40 +0100 Subject: [PATCH 24/24] randr: clear primary screen's primaryOutput when the output is deleted This fix use after free when a pluggable gpu screen (such as displaylink) was set as primary screen and unpluged. gdb backtrace: 0 OssigHandler (signo=11, sip=0x7fff2e0a50f0, unused=0x7fff2e0a4fc0) at ../../../../os/osinit.c:138 1 2 rrGetscreenResources (client=0x3195160, query=0) at ../../../../randr/rrscreen.c:577 3 0x0000000000562bae in ProcRRGetscreenResourcesCurrent (client=0x3195160) at ../../../../randr/rrscreen.c:652 4 OxOOOOB0000054de63 in ProcRRDispatch (client=0x3195160) at ../../../../randr/randr.c:717 5 0x00000000004322c6 in Dispatch () at ../../../../dix/dispatch.c:485 6 0x0900900990443139 in dix_main (argc=12, argv=0x7fff2e0a5f78, envp=0x7fff2e0a5fe0) at ../../../../dix/main.c:276 7 0X0000000000421d9a in main (argc=12, argv=0x7fff2e0a5f78, envp=0x7fff2e0a5fe0) at ../../../../dix/stubmain.c:34 --- randr/rroutput.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/randr/rroutput.c b/randr/rroutput.c index 0b4639aa6..81c49236c 100644 --- a/randr/rroutput.c +++ b/randr/rroutput.c @@ -377,6 +377,8 @@ RROutputDestroyResource(void *value, XID pid) { RROutputPtr output = (RROutputPtr) value; ScreenPtr pScreen = output->pScreen; + ScreenPtr primary; + rrScrPrivPtr primaryPriv; int m; if (pScreen) { @@ -397,6 +399,14 @@ RROutputDestroyResource(void *value, XID pid) if (pScrPriv->primaryOutput == output) pScrPriv->primaryOutput = NULL; + if (pScreen->isGPU) { + if ((primary = pScreen->current_primary)) { + primaryPriv = rrGetScrPriv(primary); + if (primaryPriv->primaryOutput == output) + primaryPriv->primaryOutput = NULL; + } + } + for (i = 0; i < pScrPriv->numOutputs; i++) { if (pScrPriv->outputs[i] == output) { memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,