Skip to content

Commit

Permalink
drm: parse edid using libdisplay-info
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Dudemanguy committed Oct 16, 2024
1 parent ade5c9b commit c045862
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 2 deletions.
6 changes: 4 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
103 changes: 103 additions & 0 deletions video/out/drm_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 = {
Expand Down
9 changes: 9 additions & 0 deletions video/out/drm_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include <xf86drm.h>
#include <xf86drmMode.h>

#include <libdisplay-info/cta.h>
#include <libdisplay-info/edid.h>
#include <libdisplay-info/info.h>

#include "video/mp_image.h"
#include "vo.h"

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit c045862

Please sign in to comment.