diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index 5d42dad5f..a952dc426 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -178,6 +178,37 @@ bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm, return true; } +static uint8_t convert_cta861_eotf(enum wlr_color_transfer_function tf) { + switch (tf) { + case WLR_COLOR_TRANSFER_FUNCTION_SRGB: + abort(); // unsupported + case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ: + return 2; + } + abort(); // unreachable +} + +static bool create_hdr_output_metadata_blob(struct wlr_drm_backend *drm, + const struct wlr_output_image_description *img_desc, uint32_t *blob_id) { + if (img_desc == NULL) { + *blob_id = 0; + return true; + } + + struct hdr_output_metadata metadata = { + .metadata_type = 0, + .hdmi_metadata_type1 = { + .eotf = convert_cta861_eotf(img_desc->transfer_function), + .metadata_type = 0, + }, + }; + if (drmModeCreatePropertyBlob(drm->fd, &metadata, sizeof(metadata), blob_id) != 0) { + wlr_log_errno(WLR_ERROR, "Failed to create HDR_OUTPUT_METADATA property"); + return false; + } + return true; +} + static uint64_t convert_primaries_to_colorspace(uint32_t primaries) { switch (primaries) { case 0: @@ -318,12 +349,19 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo state->base->image_description ? state->base->image_description->primaries : 0); } + uint32_t hdr_output_metadata = conn->hdr_output_metadata; + if ((state->base->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION) && + !create_hdr_output_metadata_blob(drm, state->base->image_description, &hdr_output_metadata)) { + return false; + } + state->mode_id = mode_id; state->gamma_lut = gamma_lut; state->fb_damage_clips = fb_damage_clips; state->primary_in_fence_fd = in_fence_fd; state->vrr_enabled = vrr_enabled; state->colorspace = colorspace; + state->hdr_output_metadata = hdr_output_metadata; return true; } @@ -338,6 +376,7 @@ void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) { crtc->own_mode_id = true; commit_blob(drm, &crtc->mode_id, state->mode_id); commit_blob(drm, &crtc->gamma_lut, state->gamma_lut); + commit_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata); conn->output.adaptive_sync_status = state->vrr_enabled ? WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED : WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED; @@ -363,6 +402,7 @@ void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) rollback_blob(drm, &crtc->mode_id, state->mode_id); rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut); + rollback_blob(drm, &conn->hdr_output_metadata, state->hdr_output_metadata); destroy_blob(drm, state->fb_damage_clips); if (state->primary_in_fence_fd >= 0) { @@ -457,6 +497,9 @@ static void atomic_connector_add(struct atomic *atom, if (conn->props.colorspace != 0) { atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace); } + if (conn->props.hdr_output_metadata != 0) { + atomic_add(atom, conn->id, conn->props.hdr_output_metadata, state->hdr_output_metadata); + } atomic_add(atom, crtc->id, crtc->props.mode_id, state->mode_id); atomic_add(atom, crtc->id, crtc->props.active, active); if (active) { diff --git a/backend/drm/properties.c b/backend/drm/properties.c index ca48c0d57..314023954 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -25,6 +25,7 @@ static const struct prop_info connector_info[] = { { "Colorspace", INDEX(colorspace) }, { "DPMS", INDEX(dpms) }, { "EDID", INDEX(edid) }, + { "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) }, { "PATH", INDEX(path) }, { "content type", INDEX(content_type) }, { "link-status", INDEX(link_status) }, diff --git a/backend/drm/util.c b/backend/drm/util.c index 365ebbe08..dd2b37351 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -89,6 +89,11 @@ void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) output->supported_primaries |= WLR_COLOR_NAMED_PRIMARIES_BT2020; } + const struct di_hdr_static_metadata *hdr_static_metadata = di_info_get_hdr_static_metadata(info); + if (conn->props.hdr_output_metadata != 0 && hdr_static_metadata->type1 && hdr_static_metadata->pq) { + output->supported_transfer_functions |= WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ; + } + di_info_destroy(info); } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index c8f26184b..af4231f54 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -159,6 +159,7 @@ struct wlr_drm_connector_state { int primary_in_fence_fd, out_fence_fd; bool vrr_enabled; uint32_t colorspace; + uint32_t hdr_output_metadata; }; /** @@ -215,6 +216,7 @@ struct wlr_drm_connector { // Atomic modesetting only uint32_t colorspace; + uint32_t hdr_output_metadata; int32_t refresh; }; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 870ea4379..c02d655ba 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -27,6 +27,7 @@ struct wlr_drm_connector_props { uint32_t crtc_id; uint32_t colorspace; + uint32_t hdr_output_metadata; }; struct wlr_drm_crtc_props {