1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-17 20:34:58 +00:00

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.
This commit is contained in:
Dudemanguy 2024-10-16 15:58:53 -05:00
parent 8039128693
commit a4d9bdd262
3 changed files with 99 additions and 4 deletions

View File

@ -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', version: '>= 0.1.1', 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',

View File

@ -617,6 +617,83 @@ success:
return true;
}
static void setup_edid(struct vo_drm_state *drm)
{
drmModePropertyBlobRes *blob = NULL;
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);
while (*exts && !(cta = di_edid_ext_get_cta(*exts++)));
if (!cta) {
MP_VERBOSE(drm, "Unable to find CTA-861 extension block.\n");
goto done;
}
const struct di_cta_data_block *const *blocks = di_edid_cta_get_data_blocks(cta);
for (int i = 0; *blocks && blocks[i]; ++i) {
if (!drm->colorimetry)
drm->colorimetry = di_cta_data_block_get_colorimetry(blocks[i]);
if (!drm->hdr_static_metadata)
drm->hdr_static_metadata = di_cta_data_block_get_hdr_static_metadata(blocks[i]);
if (drm->colorimetry && 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->colorimetry || !drm->hdr_static_metadata)
return false;
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;
if (!pl_color_transfer_is_hdr(trc) && !hdr_static_metadata->eotfs->traditional_sdr)
return false;
if (pl_color_transfer_is_hdr(trc) && !drm->colorimetry->bt2020_rgb)
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') {
@ -1034,6 +1111,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");
@ -1079,6 +1158,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);
@ -1283,10 +1365,11 @@ bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr)
destroy_hdr_blob(drm);
drm->target_params = target_params;
bool use_sdr = !target_params_supported_by_display(drm) || force_sdr;
// For any HDR, the BT2020 drm colorspace is the only one that works in practice.
struct drm_atomic_context *atomic_ctx = drm->atomic_context;
int colorspace = !force_sdr && pl_color_space_is_hdr(&drm->target_params.color) ?
int colorspace = !use_sdr && pl_color_space_is_hdr(&drm->target_params.color) ?
DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT;
drm_object_set_property(atomic_ctx->request, atomic_ctx->connector, "Colorspace", colorspace);
@ -1295,7 +1378,7 @@ bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr)
.metadata_type = HDMI_STATIC_METADATA_TYPE1,
.hdmi_metadata_type1.metadata_type = HDMI_STATIC_METADATA_TYPE1,
.hdmi_metadata_type1.eotf = force_sdr ? HDMI_EOTF_TRADITIONAL_GAMMA_SDR : eotf_map[target_params.color.transfer],
.hdmi_metadata_type1.eotf = use_sdr ? HDMI_EOTF_TRADITIONAL_GAMMA_SDR : eotf_map[target_params.color.transfer],
.hdmi_metadata_type1.display_primaries[0].x = lrintf(hdr->prim.red.x * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[0].y = lrintf(hdr->prim.red.y * DRM_PRIM_FACTOR),

View File

@ -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"
@ -129,6 +133,12 @@ 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;
const struct di_cta_colorimetry_block *colorimetry;
bool active;
bool paused;
bool still;