From 18d23950246a8ca2ea70e6d874b6f1818be4f9bd Mon Sep 17 00:00:00 2001 From: notbabaisyou Date: Mon, 23 Mar 2026 21:41:44 +0100 Subject: [PATCH] modesetting: Cache EDID data in drmmode_output_get_modes This reduces the amount of spam in the logs when RANDR or anything else tries to get the supported display modes. Doesn't prevent the frame hitches however, as this would require more work within RANDR to cache and only fetch new data if needed, which very likely would require new ABI, a.k.a good luck with that. --- .../drivers/modesetting/drmmode_display.c | 74 ++++++++++++++++--- .../drivers/modesetting/drmmode_display.h | 4 + 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 67b225ca5..30254653b 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2896,42 +2896,90 @@ drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes) return xf86ModesAdd(Modes, m); } +static inline void +drmmode_clear_edid_cache(drmmode_output_private_ptr drmmode_output) +{ + /* Free old cached data */ + if (drmmode_output->cached_edid) { + free(drmmode_output->cached_edid); + drmmode_output->cached_edid = NULL; + } + + if (drmmode_output->cached_edid_data) { + free(drmmode_output->cached_edid_data); + drmmode_output->cached_edid_data = NULL; + drmmode_output->cached_edid_length = 0; + } +} + static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) { drmmode_output_private_ptr drmmode_output = output->driver_private; drmModeConnectorPtr koutput = drmmode_output->mode_output; drmmode_ptr drmmode = drmmode_output->drmmode; + Bool edid_changed = FALSE; int i; DisplayModePtr Modes = NULL, Mode; xf86MonPtr mon = NULL; + drmModePropertyBlobPtr current_blob; if (!koutput) return NULL; + /* Free previous EDID blob from last call */ drmModeFreePropertyBlob(drmmode_output->edid_blob); + drmmode_output->edid_blob = NULL; + + current_blob = koutput_get_prop_blob(drmmode->fd, koutput, "EDID"); + if (current_blob) { + /* Check if EDID actually changed by comparing raw data */ + if (drmmode_output->cached_edid_data && + current_blob->length == drmmode_output->cached_edid_length && + memcmp(current_blob->data, drmmode_output->cached_edid_data, + current_blob->length) == 0) { + mon = drmmode_output->cached_edid; + drmmode_output->edid_blob = current_blob; + } else { + edid_changed = TRUE; + + mon = xf86InterpretEDID(output->scrn->scrnIndex, + current_blob->data); + if (mon && current_blob->length > 128) + mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + + /* Free old cached data */ + drmmode_clear_edid_cache(drmmode_output); + + /* Cache the new EDID and its raw data */ + drmmode_output->cached_edid = mon; + drmmode_output->cached_edid_data = malloc(current_blob->length); + if (drmmode_output->cached_edid_data) { + memcpy(drmmode_output->cached_edid_data, + current_blob->data, + current_blob->length); + drmmode_output->cached_edid_length = current_blob->length; + } else { + drmmode_output->cached_edid_length = 0; + } - /* look for an EDID property */ - drmmode_output->edid_blob = - koutput_get_prop_blob(drmmode->fd, koutput, "EDID"); + drmmode_output->edid_blob = current_blob; + } + } else { + return NULL; + } - if (drmmode_output->edid_blob) { - mon = xf86InterpretEDID(output->scrn->scrnIndex, - drmmode_output->edid_blob->data); - if (mon && drmmode_output->edid_blob->length > 128) - mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + /* Only call xf86OutputSetEDID if EDID actually changed */ + if (edid_changed) { + xf86OutputSetEDID(output, mon); } - xf86OutputSetEDID(output, mon); drmmode_output_attach_tile(output); - /* modes should already be available */ for (i = 0; i < koutput->count_modes; i++) { Mode = XNFalloc(sizeof(DisplayModeRec)); - drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); Modes = xf86ModesAdd(Modes, Mode); - } return drmmode_output_add_gtf_modes(output, Modes); @@ -2946,6 +2994,8 @@ drmmode_output_destroy(xf86OutputPtr output) drmModeFreePropertyBlob(drmmode_output->edid_blob); drmModeFreePropertyBlob(drmmode_output->tile_blob); + drmmode_clear_edid_cache(drmmode_output); + for (i = 0; i < drmmode_output->num_props; i++) { drmModeFreeProperty(drmmode_output->props[i].mode_prop); free(drmmode_output->props[i].atoms); diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index b020592f3..0965bc40e 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -266,6 +266,10 @@ typedef struct { xf86CrtcPtr current_crtc; Atom ctm_atom; struct drm_color_ctm ctm; + + xf86MonPtr cached_edid; /* Cached parsed EDID */ + void* cached_edid_data; /* Cached raw EDID bytes */ + uint32_t cached_edid_length; /* Length of cached raw data */ } drmmode_output_private_rec, *drmmode_output_private_ptr; typedef struct {