From c045862580d47bbf2ee8bff65b0513dbb995f741 Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Wed, 16 Oct 2024 15:58:53 -0500 Subject: [PATCH] drm: parse edid using libdisplay-info libdrm unfortunately doesn't give us what is actually supported by the connector in question. To do that, we would have to parse the edid blob. Use libdisplay-info to do this and make it required for drm support. Using what we get back from the library, we can do a bit of sanity checking for hdr metadata to make sure that the display in question can handle it before we try setting the metadata. Strictly speaking, libdisplay-info has stuff for dynamic metadata that we could potentially use, but as a first pass and for simplicity, only static is considered for now. --- meson.build | 6 ++- video/out/drm_common.c | 103 +++++++++++++++++++++++++++++++++++++++++ video/out/drm_common.h | 9 ++++ 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index f92ef0d569616..3230d6c81326e 100644 --- a/meson.build +++ b/meson.build @@ -935,9 +935,11 @@ if features['direct3d'] endif drm = dependency('libdrm', version: '>= 2.4.105', required: get_option('drm')) -features += {'drm': drm.found() and (features['vt.h'] or features['consio.h'] or features['wsdisplay-usl-io.h'])} +libdisplay_info = dependency('libdisplay-info', required: get_option('drm')) +features += {'drm': drm.found() and libdisplay_info.found() and + (features['vt.h'] or features['consio.h'] or features['wsdisplay-usl-io.h'])} if features['drm'] - dependencies += drm + dependencies += [drm, libdisplay_info] sources += files('video/drmprime.c', 'video/out/drm_atomic.c', 'video/out/drm_common.c', diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 95bbd1d6931cc..4b072139acea0 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -627,6 +627,100 @@ static bool setup_crtc(struct vo_drm_state *drm, const drmModeRes *res) return true; } +static void setup_edid(struct vo_drm_state *drm) +{ + drmModePropertyBlobRes *blob; + for (int i = 0; i < drm->connector->count_props; ++i) { + drmModePropertyRes *prop = drmModeGetProperty(drm->fd, drm->connector->props[i]); + if (prop && strcmp(prop->name, "EDID") == 0) { + blob = drmModeGetPropertyBlob(drm->fd, drm->connector->prop_values[i]); + } + drmModeFreeProperty(prop); + if (blob) + break; + } + if (!blob) { + MP_VERBOSE(drm, "Unable to get EDID blob from connector.\n"); + return; + } + + drm->info = di_info_parse_edid(blob->data, blob->length); + if (!drm->info) { + MP_VERBOSE(drm, "Failed to parse EDID info: %s\n", mp_strerror(errno)); + goto done; + } + + const struct di_edid *edid = di_info_get_edid(drm->info); + if (!edid) { + MP_VERBOSE(drm, "Failed to get EDID info: %s\n", mp_strerror(errno)); + goto done; + } + + drm->chromaticity = di_edid_get_chromaticity_coords(edid); + + const struct di_edid_cta *cta; + const struct di_edid_ext *const *exts = di_edid_get_extensions(edid); + for (int i = 0; exts[i]; ++i) { + if ((cta = di_edid_ext_get_cta(exts[i]))) + break; + } + + if (cta) { + const struct di_cta_data_block *const *blocks = di_edid_cta_get_data_blocks(cta); + for (int i = 0; blocks[i]; ++i) { + drm->hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(*blocks); + if (drm->hdr_static_metadata) + break; + } + } + +done: + if (blob) + drmModeFreePropertyBlob(blob); +} + +static bool target_params_supported_by_display(struct vo_drm_state *drm) +{ + if (!drm->chromaticity || !drm->hdr_static_metadata) + return false; + + const struct di_edid_chromaticity_coords *chromaticity = drm->chromaticity; + const struct di_cta_hdr_static_metadata_block *hdr_static_metadata = drm->hdr_static_metadata; + enum pl_color_transfer trc = drm->target_params.color.transfer; + const struct pl_hdr_metadata *hdr = &drm->target_params.color.hdr; + + if (hdr->prim.red.x > chromaticity->red_x) + return false; + if (hdr->prim.red.y > chromaticity->red_y) + return false; + if (hdr->prim.green.x > chromaticity->green_x) + return false; + if (hdr->prim.green.y > chromaticity->green_y) + return false; + if (hdr->prim.blue.x > chromaticity->blue_x) + return false; + if (hdr->prim.blue.y > chromaticity->blue_y) + return false; + if (hdr->prim.white.x > chromaticity->white_x) + return false; + if (hdr->prim.white.y > chromaticity->white_y) + return false; + + if (hdr->max_luma > hdr_static_metadata->desired_content_max_luminance) + return false; + + if (!pl_color_transfer_is_hdr(trc) && !hdr_static_metadata->eotfs->traditional_sdr) + return false; + + if (trc == PL_COLOR_TRC_PQ && !hdr_static_metadata->eotfs->pq) + return false; + + if (trc == PL_COLOR_TRC_HLG && !hdr_static_metadata->eotfs->hlg) + return false; + + return true; +} + static bool all_digits(const char *str) { if (str == NULL || str[0] == '\0') { @@ -1044,6 +1138,8 @@ bool vo_drm_init(struct vo *vo) if (!setup_mode(drm)) goto err; + setup_edid(drm); + // Universal planes allows accessing all the planes (including primary) if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { MP_ERR(drm, "Failed to set Universal planes capability\n"); @@ -1089,6 +1185,9 @@ void vo_drm_uninit(struct vo *vo) restore_sdr(drm); destroy_hdr_blob(drm); + if (drm->info) + di_info_destroy(drm->info); + vo_drm_release_crtc(drm); if (drm->vt_switcher_active) vt_switcher_destroy(&drm->vt_switcher); @@ -1290,6 +1389,10 @@ bool vo_drm_set_hdr_metadata(struct vo *vo) destroy_hdr_blob(drm); drm->target_params = target_params; + if (!target_params_supported_by_display(drm)) { + restore_sdr(drm); + return false; + } const struct pl_hdr_metadata *hdr = &target_params.color.hdr; struct hdr_output_metadata metadata = { diff --git a/video/out/drm_common.h b/video/out/drm_common.h index 43a48ad3790d8..b2777b338c3d7 100644 --- a/video/out/drm_common.h +++ b/video/out/drm_common.h @@ -22,6 +22,10 @@ #include #include +#include +#include +#include + #include "video/mp_image.h" #include "vo.h" @@ -102,6 +106,11 @@ struct vo_drm_state { struct vo *vo; struct vt_switcher vt_switcher; + // libdisplay-info edid stuff + struct di_info *info; + const struct di_edid_chromaticity_coords *chromaticity; + const struct di_cta_hdr_static_metadata_block *hdr_static_metadata; + bool active; bool paused; bool still;