Skip to content

Commit

Permalink
context_drm_gl: add support for hdr metadata
Browse files Browse the repository at this point in the history
It seems what we can do on this level is a bit limited but it's better
than nothing. Closes #8219.
  • Loading branch information
Dudemanguy committed Oct 16, 2024
1 parent 4c24eae commit 91aab79
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 15 deletions.
1 change: 1 addition & 0 deletions video/out/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
82 changes: 80 additions & 2 deletions video/out/drm_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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] = DRM_EOTF_TRADITIONAL_GAMMA_SDR,
[PL_COLOR_TRC_PQ] = DRM_EOTF_SMPTE_ST2084,
[PL_COLOR_TRC_HLG] = DRM_EOTF_BT_2100_HLG,
};

struct drm_mode_spec {
enum {
DRM_MODE_SPEC_BY_IDX, // Specified by idx
Expand Down Expand Up @@ -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])
{
Expand Down Expand Up @@ -496,6 +513,28 @@ 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;

destroy_hdr_blob(drm);

struct hdr_output_metadata metadata = {
.metadata_type = DRM_STATIC_METADATA_TYPE1,
.hdmi_metadata_type1.metadata_type = DRM_STATIC_METADATA_TYPE1,
.hdmi_metadata_type1.eotf = DRM_EOTF_TRADITIONAL_GAMMA_SDR,
};
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);

int ret = drmModeAtomicCommit(drm->fd, atomic_ctx->request, DRM_MODE_ATOMIC_ALLOW_MODESET, drm);
if (ret)
MP_WARN(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)
{
Expand Down Expand Up @@ -1047,6 +1086,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);
Expand All @@ -1061,9 +1103,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);
Expand Down Expand Up @@ -1240,6 +1281,43 @@ 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)
{
struct vo_drm_state *drm = vo->drm;
struct mp_image_params target_params = vo_get_target_params(vo);
if (!vo->target_params || pl_color_space_equal(&target_params.color, &drm->target_params.color))
return false;

destroy_hdr_blob(drm);
drm->target_params = target_params;

struct pl_hdr_metadata hdr = target_params.color.hdr;
struct hdr_output_metadata metadata = {
.metadata_type = DRM_STATIC_METADATA_TYPE1,
.hdmi_metadata_type1.metadata_type = DRM_STATIC_METADATA_TYPE1,

.hdmi_metadata_type1.eotf = eotf_map[target_params.color.transfer],

.hdmi_metadata_type1.display_primaries[0].x = roundf(hdr.prim.red.x * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[0].y = roundf(hdr.prim.red.y * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[1].x = roundf(hdr.prim.green.x * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[1].y = roundf(hdr.prim.green.y * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[2].x = roundf(hdr.prim.blue.x * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.display_primaries[2].y = roundf(hdr.prim.blue.y * DRM_PRIM_FACTOR),

.hdmi_metadata_type1.white_point.x = roundf(hdr.prim.white.x * DRM_PRIM_FACTOR),
.hdmi_metadata_type1.white_point.y = roundf(hdr.prim.white.y * DRM_PRIM_FACTOR),

.hdmi_metadata_type1.min_display_mastering_luminance = roundf(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);
return true;
}

void vo_drm_set_monitor_par(struct vo *vo)
{
struct vo_drm_state *drm = vo->drm;
Expand Down
23 changes: 23 additions & 0 deletions video/out/drm_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <stdbool.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

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

enum {
Expand All @@ -31,6 +33,19 @@ enum {
DRM_OPTS_FORMAT_YUYV,
};

// Copied from include/linux/hdmi.h
enum drm_metadata_type {
DRM_STATIC_METADATA_TYPE1 = 0,
};

// Copied from include/linux/hdmi.h
enum drm_eotf {
DRM_EOTF_TRADITIONAL_GAMMA_SDR,
DRM_EOTF_TRADITIONAL_GAMMA_HDR,
DRM_EOTF_SMPTE_ST2084,
DRM_EOTF_BT_2100_HLG,
};

struct framebuffer {
int fd;
uint32_t width;
Expand All @@ -42,6 +57,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;
Expand Down Expand Up @@ -72,9 +92,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;
Expand All @@ -99,6 +121,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);
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);
Expand Down
20 changes: 7 additions & 13 deletions video/out/opengl/context_drm_egl.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,17 @@ 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)) {
drm_object_set_property(atomic_ctx->request, atomic_ctx->connector, "HDR_OUTPUT_METADATA", drm->hdr.blob_id);
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));
Expand Down Expand Up @@ -457,17 +462,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);

Expand Down

0 comments on commit 91aab79

Please sign in to comment.