diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 6471357fb..706dfcab0 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 d7e91e352..46b809be3 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 7ec274a2e..6e2d29b27 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 1c9d10681..f6b4248f9 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; }