mirror of https://github.com/mpv-player/mpv
context_drm_gl: add support for hdr metadata
It seems what we can do on this level is a bit limited but it's better than nothing. Closes #8219.
This commit is contained in:
parent
a61518db98
commit
2827c9f323
|
@ -299,6 +299,7 @@ void drm_atomic_destroy_context(struct drm_atomic_context *ctx)
|
|||
drm_object_free(ctx->connector);
|
||||
drm_object_free(ctx->draw_plane);
|
||||
drm_object_free(ctx->drmprime_video_plane);
|
||||
drmModeAtomicFree(ctx->request);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
#define ACQUIRE_SIGNAL SIGUSR2
|
||||
#define MAX_CONNECTOR_NAME_LEN 20
|
||||
|
||||
#define DRM_PRIM_FACTOR 50000
|
||||
#define DRM_MIN_LUMA_FACTOR 10000
|
||||
|
||||
static int vt_switcher_pipe[2];
|
||||
|
||||
static int drm_connector_opt_help(struct mp_log *log, const struct m_option *opt,
|
||||
|
@ -135,6 +138,12 @@ static const char *connector_names[] = {
|
|||
"USB", // DRM_MODE_CONNECTOR_USB
|
||||
};
|
||||
|
||||
static int eotf_map[PL_COLOR_TRC_COUNT] = {
|
||||
[PL_COLOR_TRC_BT_1886] = HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
|
||||
[PL_COLOR_TRC_PQ] = HDMI_EOTF_SMPTE_ST2084,
|
||||
[PL_COLOR_TRC_HLG] = HDMI_EOTF_BT_2100_HLG,
|
||||
};
|
||||
|
||||
struct drm_mode_spec {
|
||||
enum {
|
||||
DRM_MODE_SPEC_BY_IDX, // Specified by idx
|
||||
|
@ -443,6 +452,14 @@ void vo_drm_release_crtc(struct vo_drm_state *drm)
|
|||
}
|
||||
|
||||
/* libdrm */
|
||||
static void destroy_hdr_blob(struct vo_drm_state *drm)
|
||||
{
|
||||
if (drm->hdr.blob_id) {
|
||||
drmModeDestroyPropertyBlob(drm->fd, drm->hdr.blob_id);
|
||||
drm->hdr.blob_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_connector_name(const drmModeConnector *connector,
|
||||
char ret[MAX_CONNECTOR_NAME_LEN])
|
||||
{
|
||||
|
@ -496,6 +513,18 @@ static drmModeConnector *get_first_connected_connector(const drmModeRes *res,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void restore_sdr(struct vo_drm_state *drm)
|
||||
{
|
||||
struct drm_atomic_context *atomic_ctx = drm->atomic_context;
|
||||
if (!atomic_ctx)
|
||||
return;
|
||||
|
||||
vo_drm_set_hdr_metadata(drm->vo, true);
|
||||
int ret = drmModeAtomicCommit(drm->fd, atomic_ctx->request, DRM_MODE_ATOMIC_ALLOW_MODESET, drm);
|
||||
if (ret)
|
||||
MP_VERBOSE(drm, "Failed to commit atomic request: %s\n", mp_strerror(ret));
|
||||
}
|
||||
|
||||
static bool setup_connector(struct vo_drm_state *drm, const drmModeRes *res,
|
||||
const char *connector_name)
|
||||
{
|
||||
|
@ -1047,6 +1076,9 @@ void vo_drm_uninit(struct vo *vo)
|
|||
if (!drm)
|
||||
return;
|
||||
|
||||
restore_sdr(drm);
|
||||
destroy_hdr_blob(drm);
|
||||
|
||||
vo_drm_release_crtc(drm);
|
||||
if (drm->vt_switcher_active)
|
||||
vt_switcher_destroy(&drm->vt_switcher);
|
||||
|
@ -1061,9 +1093,8 @@ void vo_drm_uninit(struct vo *vo)
|
|||
drmModeFreeEncoder(drm->encoder);
|
||||
drm->encoder = NULL;
|
||||
}
|
||||
if (drm->atomic_context) {
|
||||
if (drm->atomic_context)
|
||||
drm_atomic_destroy_context(drm->atomic_context);
|
||||
}
|
||||
|
||||
close(drm->fd);
|
||||
talloc_free(drm);
|
||||
|
@ -1242,6 +1273,51 @@ double vo_drm_get_display_fps(struct vo_drm_state *drm)
|
|||
return mode_get_Hz(&drm->mode.mode);
|
||||
}
|
||||
|
||||
bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr)
|
||||
{
|
||||
struct vo_drm_state *drm = vo->drm;
|
||||
struct mp_image_params target_params = vo_get_target_params(vo);
|
||||
if (!force_sdr && (pl_color_space_equal(&target_params.color, &drm->target_params.color) ||
|
||||
!target_params.w || !target_params.h))
|
||||
return false;
|
||||
|
||||
destroy_hdr_blob(drm);
|
||||
drm->target_params = target_params;
|
||||
|
||||
// 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) ?
|
||||
DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT;
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->connector, "Colorspace", colorspace);
|
||||
|
||||
const struct pl_hdr_metadata *hdr = &target_params.color.hdr;
|
||||
struct hdr_output_metadata metadata = {
|
||||
.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.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),
|
||||
.hdmi_metadata_type1.display_primaries[1].x = lrintf(hdr->prim.green.x * DRM_PRIM_FACTOR),
|
||||
.hdmi_metadata_type1.display_primaries[1].y = lrintf(hdr->prim.green.y * DRM_PRIM_FACTOR),
|
||||
.hdmi_metadata_type1.display_primaries[2].x = lrintf(hdr->prim.blue.x * DRM_PRIM_FACTOR),
|
||||
.hdmi_metadata_type1.display_primaries[2].y = lrintf(hdr->prim.blue.y * DRM_PRIM_FACTOR),
|
||||
|
||||
.hdmi_metadata_type1.white_point.x = lrintf(hdr->prim.white.x * DRM_PRIM_FACTOR),
|
||||
.hdmi_metadata_type1.white_point.y = lrintf(hdr->prim.white.y * DRM_PRIM_FACTOR),
|
||||
|
||||
.hdmi_metadata_type1.min_display_mastering_luminance = lrintf(hdr->min_luma * DRM_MIN_LUMA_FACTOR),
|
||||
.hdmi_metadata_type1.max_display_mastering_luminance = hdr->max_luma,
|
||||
|
||||
.hdmi_metadata_type1.max_cll = hdr->max_cll,
|
||||
.hdmi_metadata_type1.max_fall = hdr->max_fall,
|
||||
};
|
||||
drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), &drm->hdr.blob_id);
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->connector, "HDR_OUTPUT_METADATA", drm->hdr.blob_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
void vo_drm_set_monitor_par(struct vo *vo)
|
||||
{
|
||||
struct vo_drm_state *drm = vo->drm;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "video/mp_image.h"
|
||||
#include "vo.h"
|
||||
|
||||
enum {
|
||||
|
@ -31,6 +33,46 @@ enum {
|
|||
DRM_OPTS_FORMAT_YUYV,
|
||||
};
|
||||
|
||||
// Enum values based on include/linux/hdmi.h
|
||||
// and https://docs.kernel.org/gpu/drm-uapi.html
|
||||
// for interoperability with drm API.
|
||||
enum drm_metadata_type {
|
||||
HDMI_STATIC_METADATA_TYPE1 = 0,
|
||||
};
|
||||
|
||||
// Enum values based on https://docs.kernel.org/gpu/drm-kms.html
|
||||
// for interoperability with drm API.
|
||||
enum drm_colorspace {
|
||||
DRM_MODE_COLORIMETRY_DEFAULT = 0,
|
||||
DRM_MODE_COLORIMETRY_NO_DATA = 0,
|
||||
DRM_MODE_COLORIMETRY_SMPTE_170M_YCC = 1,
|
||||
DRM_MODE_COLORIMETRY_BT709_YCC = 2,
|
||||
DRM_MODE_COLORIMETRY_XVYCC_601 = 3,
|
||||
DRM_MODE_COLORIMETRY_XVYCC_709 = 4,
|
||||
DRM_MODE_COLORIMETRY_SYCC_601 = 5,
|
||||
DRM_MODE_COLORIMETRY_OPYCC_601 = 6,
|
||||
DRM_MODE_COLORIMETRY_OPRGB = 7,
|
||||
DRM_MODE_COLORIMETRY_BT2020_CYCC = 8,
|
||||
DRM_MODE_COLORIMETRY_BT2020_RGB = 9,
|
||||
DRM_MODE_COLORIMETRY_BT2020_YCC = 10,
|
||||
DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 = 11,
|
||||
DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER = 12,
|
||||
DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED = 13,
|
||||
DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT = 14,
|
||||
DRM_MODE_COLORIMETRY_BT601_YCC = 15,
|
||||
DRM_MODE_COLORIMETRY_COUNT,
|
||||
};
|
||||
|
||||
// Enum values based on include/linux/hdmi.h
|
||||
// and https://docs.kernel.org/gpu/drm-uapi.html
|
||||
// for interoperability with drm API.
|
||||
enum drm_eotf {
|
||||
HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
|
||||
HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
|
||||
HDMI_EOTF_SMPTE_ST2084,
|
||||
HDMI_EOTF_BT_2100_HLG,
|
||||
};
|
||||
|
||||
struct framebuffer {
|
||||
int fd;
|
||||
uint32_t width;
|
||||
|
@ -42,6 +84,11 @@ struct framebuffer {
|
|||
uint32_t id;
|
||||
};
|
||||
|
||||
struct drm_hdr {
|
||||
struct hdr_output_metadata metadata;
|
||||
uint32_t blob_id;
|
||||
};
|
||||
|
||||
struct drm_mode {
|
||||
drmModeModeInfo mode;
|
||||
uint32_t blob_id;
|
||||
|
@ -72,9 +119,11 @@ struct vo_drm_state {
|
|||
drmEventContext ev;
|
||||
|
||||
struct drm_atomic_context *atomic_context;
|
||||
struct drm_hdr hdr;
|
||||
struct drm_mode mode;
|
||||
struct drm_opts *opts;
|
||||
struct framebuffer *fb;
|
||||
struct mp_image_params target_params;
|
||||
struct mp_log *log;
|
||||
struct mp_present *present;
|
||||
struct vo *vo;
|
||||
|
@ -99,6 +148,7 @@ bool vo_drm_init(struct vo *vo);
|
|||
int vo_drm_control(struct vo *vo, int *events, int request, void *arg);
|
||||
|
||||
double vo_drm_get_display_fps(struct vo_drm_state *drm);
|
||||
bool vo_drm_set_hdr_metadata(struct vo *vo, bool force_sdr);
|
||||
void vo_drm_set_monitor_par(struct vo *vo);
|
||||
void vo_drm_uninit(struct vo *vo);
|
||||
void vo_drm_wait_events(struct vo *vo, int64_t until_time_ns);
|
||||
|
|
|
@ -319,12 +319,15 @@ static void queue_flip(struct ra_ctx *ctx, struct gbm_frame *frame)
|
|||
update_framebuffer_from_bo(ctx, frame->bo);
|
||||
|
||||
struct drm_atomic_context *atomic_ctx = drm->atomic_context;
|
||||
int flags = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT;
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->draw_plane, "FB_ID", drm->fb->id);
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->draw_plane, "CRTC_ID", atomic_ctx->crtc->id);
|
||||
drm_object_set_property(atomic_ctx->request, atomic_ctx->draw_plane, "ZPOS", 1);
|
||||
|
||||
int ret = drmModeAtomicCommit(drm->fd, atomic_ctx->request,
|
||||
DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, drm);
|
||||
if (vo_drm_set_hdr_metadata(ctx->vo, false))
|
||||
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
|
||||
int ret = drmModeAtomicCommit(drm->fd, atomic_ctx->request, flags, drm);
|
||||
|
||||
if (ret)
|
||||
MP_WARN(ctx->vo, "Failed to commit atomic request: %s\n", mp_strerror(ret));
|
||||
|
@ -457,17 +460,6 @@ static const struct ra_swapchain_fns drm_egl_swapchain = {
|
|||
static void drm_egl_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo_drm_state *drm = ctx->vo->drm;
|
||||
if (drm) {
|
||||
struct drm_atomic_context *atomic_ctx = drm->atomic_context;
|
||||
|
||||
if (drmModeAtomicCommit(drm->fd, atomic_ctx->request, 0, NULL))
|
||||
MP_ERR(ctx->vo, "Failed to commit atomic request: %s\n",
|
||||
mp_strerror(errno));
|
||||
|
||||
drmModeAtomicFree(atomic_ctx->request);
|
||||
}
|
||||
|
||||
ra_gl_ctx_uninit(ctx);
|
||||
vo_drm_uninit(ctx->vo);
|
||||
|
||||
|
|
Loading…
Reference in New Issue