From 2c0a9c064a28bfef676f9a907a58f58dbd620e1b Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 31 Aug 2023 13:58:17 +0300 Subject: [PATCH] backend-drm: store EDID data Store the EDID data as-is, so that we can tell when the EDID blob has changed. This is not too useful yet, because all the weston_head_set_*() API raises the device_changed flag only if the information actually changes. However, I want to expose the libdisplay-info di_info structure through weston_head, and those cannot be (as) easily compared. We need to know when the EDID blob changes, so we can call weston_head_set_device_changed() appropriately when updating di_info. Signed-off-by: Pekka Paalanen --- libweston/backend-drm/drm-internal.h | 3 ++ libweston/backend-drm/drm.c | 1 + libweston/backend-drm/modes.c | 58 +++++++++++++++++++--------- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 8542bd0c..c06a5bbc 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -616,6 +616,9 @@ struct drm_head { /* drm_output::disable_head */ struct wl_list disable_head_link; + + void *display_data; /**< EDID or DisplayID blob */ + size_t display_data_len; /**< bytes */ }; struct drm_crtc { diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 81666b5c..bb8c431f 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -2704,6 +2704,7 @@ drm_head_destroy(struct weston_head *base) if (head->backlight) backlight_destroy(head->backlight); + free(head->display_data); free(head); } diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c index 7b431199..b4ade8cc 100644 --- a/libweston/backend-drm/modes.c +++ b/libweston/backend-drm/modes.c @@ -384,37 +384,55 @@ drm_head_info_from_edid(struct drm_head_info *dhi, #endif /* HAVE_LIBDISPLAY_INFO else */ -/** Parse monitor make, model and serial from EDID - * - * \param head The head whose \c drm_edid to fill in. - * \param props The DRM connector properties to get the EDID from. - * \param[out] dhi Receives information from EDID. - * - * \c *dhi must be drm_head_info_fini()'d by the caller. - */ static void -find_and_parse_output_edid(struct drm_head *head, - drmModeObjectPropertiesPtr props, - struct drm_head_info *dhi) +drm_head_set_display_data(struct drm_head *head, const void *data, size_t len) +{ + free(head->display_data); + + if (!data || len == 0) { + head->display_data = NULL; + head->display_data_len = 0; + return; + } + + head->display_data = xmalloc(len); + head->display_data_len = len; + memcpy(head->display_data, data, len); +} + +static bool +drm_head_maybe_update_display_data(struct drm_head *head, + drmModeObjectPropertiesPtr props) { struct drm_device *device = head->connector.device; drmModePropertyBlobPtr edid_blob = NULL; uint32_t blob_id; + bool changed = false; blob_id = drm_property_get_value( &head->connector.props[WDRM_CONNECTOR_EDID], props, 0); - if (!blob_id) - return; + if (blob_id) + edid_blob = drmModeGetPropertyBlob(device->drm.fd, blob_id); - edid_blob = drmModeGetPropertyBlob(device->drm.fd, blob_id); - if (!edid_blob) - return; - - drm_head_info_from_edid(dhi, edid_blob->data, edid_blob->length); + if (edid_blob && edid_blob->length > 0) { + if (!head->display_data || + head->display_data_len != edid_blob->length || + memcmp(head->display_data, edid_blob->data, edid_blob->length)) { + drm_head_set_display_data(head, edid_blob->data, edid_blob->length); + changed = true; + } + } else { + if (head->display_data) { + drm_head_set_display_data(head, NULL, 0); + changed = true; + } + } drmModeFreePropertyBlob(edid_blob); + + return changed; } static void @@ -597,7 +615,9 @@ update_head_from_connector(struct drm_head *head) drmModeConnector *conn = connector->conn; struct drm_head_info dhi = { .eotf_mask = WESTON_EOTF_MODE_SDR }; - find_and_parse_output_edid(head, props, &dhi); + drm_head_maybe_update_display_data(head, props); + + drm_head_info_from_edid(&dhi, head->display_data, head->display_data_len); weston_head_set_monitor_strings(&head->base, dhi.make, dhi.model,