From 5151f9fe9e9bacc6860931af60adba28cfd431a7 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 14 Jul 2021 15:01:48 +0300 Subject: [PATCH] backend-drm: program HDR_OUTPUT_METADATA Program the connector property HDR_OUTPUT_METADATA based on the EOTF mode of the output. For now, this changes only the EOTF. The colorimetry and luminance are left undefined, to be filled in by later patches. This should still be enough to put a video sink into HDR mode, albeit the response is probably unknown. drm_output keeps track of the currently existing blob id. If the blob contents need to be re-created, this blob would be destroyed and the field set to zero. In this patch, there is no provision for runtime changing of HDR metadata, so there is no code doing that. Destroying the blob at arbitrary times is not a problem, because the kernel keeps a reference to the data as long as the blob id remains with KMS. Signed-off-by: Pekka Paalanen --- libweston/backend-drm/drm-internal.h | 2 + libweston/backend-drm/drm.c | 77 ++++++++++++++++++++++++++++ libweston/backend-drm/kms.c | 10 +++- libweston/backend-drm/modes.c | 2 +- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 6471357f..706dfcab 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -549,6 +549,8 @@ struct drm_output { uint32_t gbm_format; uint32_t gbm_bo_flags; + uint32_t hdr_output_metadata_blob_id; + /* Plane being displayed directly on the CRTC */ struct drm_plane *scanout_plane; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index d7e91e35..46b809be 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -51,6 +51,7 @@ #include #include #include "drm-internal.h" +#include "libdrm-updates.h" #include "shared/helpers.h" #include "shared/timespec-util.h" #include "shared/string-helpers.h" @@ -440,6 +441,71 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) pixman_region32_fini(&scanout_damage); } +static int +drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output) +{ + struct hdr_output_metadata meta; + uint32_t blob_id = 0; + int ret; + + if (output->hdr_output_metadata_blob_id) + return 0; + + /* + * Set up the data for Dynamic Range and Mastering InfoFrame, + * CTA-861-G, a.k.a the static HDR metadata. + */ + + memset(&meta, 0, sizeof meta); + + meta.metadata_type = 0; /* Static Metadata Type 1 */ + + /* Duplicated field in UABI struct */ + meta.hdmi_metadata_type1.metadata_type = meta.metadata_type; + + switch (output->base.eotf_mode) { + case WESTON_EOTF_MODE_NONE: + assert(0 && "bad eotf_mode: none"); + return -1; + case WESTON_EOTF_MODE_SDR: + /* + * Do not send any static HDR metadata. Video sinks should + * respond by switching to traditional SDR mode. If they + * do not, the kernel should fix that up. + */ + assert(output->hdr_output_metadata_blob_id == 0); + return 0; + case WESTON_EOTF_MODE_TRADITIONAL_HDR: + meta.hdmi_metadata_type1.eotf = 1; /* from CTA-861-G */ + break; + case WESTON_EOTF_MODE_ST2084: + meta.hdmi_metadata_type1.eotf = 2; /* from CTA-861-G */ + break; + case WESTON_EOTF_MODE_HLG: + meta.hdmi_metadata_type1.eotf = 3; /* from CTA-861-G */ + break; + } + + if (meta.hdmi_metadata_type1.eotf == 0) { + assert(0 && "bad eotf_mode"); + return -1; + } + + /* The other fields are intentionally left as zeroes. */ + + ret = drmModeCreatePropertyBlob(output->backend->drm.fd, + &meta, sizeof meta, &blob_id); + if (ret != 0) { + weston_log("Error: failed to create KMS blob for HDR metadata on output '%s': %s\n", + output->base.name, strerror(-ret)); + return -1; + } + + output->hdr_output_metadata_blob_id = blob_id; + + return 0; +} + static int drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) { @@ -474,6 +540,9 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) else state->protection = WESTON_HDCP_DISABLE; + if (drm_output_ensure_hdr_output_metadata_blob(output) < 0) + goto err; + drm_output_render(state, damage); scanout_state = drm_output_state_get_plane(state, output->scanout_plane); @@ -1845,6 +1914,12 @@ drm_output_deinit(struct weston_output *base) drm_output_deinit_planes(output); drm_output_detach_crtc(output); + + if (output->hdr_output_metadata_blob_id) { + drmModeDestroyPropertyBlob(b->drm.fd, + output->hdr_output_metadata_blob_id); + output->hdr_output_metadata_blob_id = 0; + } } static void @@ -1879,6 +1954,8 @@ drm_output_destroy(struct weston_output *base) assert(!output->state_last); drm_output_state_free(output->state_cur); + assert(output->hdr_output_metadata_blob_id == 0); + free(output); } diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index 7ec274a2..6e2d29b2 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -973,10 +973,18 @@ drm_output_apply_state_atomic(struct drm_output_state *state, WDRM_CONNECTOR_CRTC_ID, 0); } - wl_list_for_each(head, &output->base.head_list, base.output_link) + wl_list_for_each(head, &output->base.head_list, base.output_link) { drm_connector_set_hdcp_property(&head->connector, state->protection, req); + if (drm_connector_has_prop(&head->connector, + WDRM_CONNECTOR_HDR_OUTPUT_METADATA)) { + ret |= connector_add_prop(req, &head->connector, + WDRM_CONNECTOR_HDR_OUTPUT_METADATA, + output->hdr_output_metadata_blob_id); + } + } + if (ret != 0) { weston_log("couldn't set atomic CRTC/connector state\n"); return ret; diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c index 1c9d1068..f6b4248f 100644 --- a/libweston/backend-drm/modes.c +++ b/libweston/backend-drm/modes.c @@ -360,7 +360,7 @@ prune_eotf_modes_by_kms_support(struct drm_head *head, uint32_t *eotf_mask) /* Without the KMS property, cannot do anything but SDR. */ info = &head->connector.props[WDRM_CONNECTOR_HDR_OUTPUT_METADATA]; - if (info->prop_id == 0) + if (!head->backend->atomic_modeset || info->prop_id == 0) *eotf_mask = WESTON_EOTF_MODE_SDR; }