From 5f9b68d68f80769ebdb3fe9fbd9cb42eae03bc0f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 8 Jul 2021 14:47:54 +0300 Subject: [PATCH] libweston: introduce weston_eotf_mode This is the switch to turn HDR mode on. The values in the enumeration come straight from CTA-861-G standard. Monitors advertise support for some of the HDR modes in their EDID, and I am not aware of any other way to detect if a HDR mode actually works or not. Different monitors may support different and multiple modes. Different modes may look different. Therefore the high-level choice of how to drive a HDR video sink is left for the Weston frontend to decide. All the details like what HDR metadata to use are left for the color manager. This commit adds the libweston API for backends to advertise support and for frontends to choose a mode. Backend and frontend implementations follow in other commits. The frontend API does not limit the EOTF mode to the supported ones to allow experimentation and overriding EDID. Signed-off-by: Pekka Paalanen --- include/libweston/libweston.h | 46 +++++++++++++++ libweston/backend.h | 4 ++ libweston/color.c | 17 ++++++ libweston/color.h | 3 + libweston/compositor.c | 102 ++++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+) diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index 58097205..f881b94f 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -207,6 +207,40 @@ struct weston_testsuite_data { void *test_private_data; }; +/** EOTF mode for outputs and heads + * + * A list of EOTF modes for driving displays, defined by CTA-861-G for + * Dynamic Range and Mastering InfoFrame. + * + * On heads, a bitmask of one or more entries shows which modes are claimed + * supported. + * + * On outputs, the mode to be used for driving the video sink. + * + * For traditional non-HDR sRGB, use WESTON_EOTF_MODE_SDR. + */ +enum weston_eotf_mode { + /** Invalid EOTF mode, or none supported. */ + WESTON_EOTF_MODE_NONE = 0, + + /** Traditional gamma, SDR luminance range */ + WESTON_EOTF_MODE_SDR = 0x01, + + /** Traditional gamma, HDR luminance range */ + WESTON_EOTF_MODE_TRADITIONAL_HDR = 0x02, + + /** Preceptual quantizer, SMPTE ST 2084 */ + WESTON_EOTF_MODE_ST2084 = 0x04, + + /** Hybrid log-gamma, ITU-R BT.2100 */ + WESTON_EOTF_MODE_HLG = 0x08, +}; + +/** Bitmask of all defined EOTF modes */ +#define WESTON_EOTF_MODE_ALL_MASK \ + ((uint32_t)(WESTON_EOTF_MODE_SDR | WESTON_EOTF_MODE_TRADITIONAL_HDR | \ + WESTON_EOTF_MODE_ST2084 | WESTON_EOTF_MODE_HLG)) + /** Represents a head, usually a display connector * * \rst @@ -243,6 +277,7 @@ struct weston_head { char *name; /**< head name, e.g. connector name */ bool connected; /**< is physically connected */ bool non_desktop; /**< non-desktop display, e.g. HMD */ + uint32_t supported_eotf_mask; /**< supported weston_eotf_mode bits */ /** Current content protection status */ enum weston_hdcp_protection current_protection; @@ -361,6 +396,7 @@ struct weston_output { struct weston_color_transform *from_sRGB_to_blend; struct weston_color_transform *from_blend_to_output; bool from_blend_to_output_by_backend; + enum weston_eotf_mode eotf_mode; int (*enable)(struct weston_output *output); int (*disable)(struct weston_output *output); @@ -2107,6 +2143,13 @@ bool weston_output_set_color_profile(struct weston_output *output, struct weston_color_profile *cprof); +void +weston_output_set_eotf_mode(struct weston_output *output, + enum weston_eotf_mode eotf_mode); + +enum weston_eotf_mode +weston_output_get_eotf_mode(const struct weston_output *output); + void weston_output_init(struct weston_output *output, struct weston_compositor *compositor, @@ -2121,6 +2164,9 @@ weston_output_enable(struct weston_output *output); void weston_output_disable(struct weston_output *output); +uint32_t +weston_output_get_supported_eotf_modes(struct weston_output *output); + void weston_compositor_flush_heads_changed(struct weston_compositor *compositor); diff --git a/libweston/backend.h b/libweston/backend.h index 4b19b399..26624cf9 100644 --- a/libweston/backend.h +++ b/libweston/backend.h @@ -136,6 +136,10 @@ weston_head_set_subpixel(struct weston_head *head, void weston_head_set_transform(struct weston_head *head, uint32_t transform); +void +weston_head_set_supported_eotf_mask(struct weston_head *head, + uint32_t eotf_mask); + /* weston_output */ void diff --git a/libweston/color.c b/libweston/color.c index eb1d45eb..c2605fd7 100644 --- a/libweston/color.c +++ b/libweston/color.c @@ -297,3 +297,20 @@ out_close: close(fd); return cprof; } + +/** Get a string naming the EOTF mode + * + * \internal + */ +WL_EXPORT const char * +weston_eotf_mode_to_str(enum weston_eotf_mode e) +{ + switch (e) { + case WESTON_EOTF_MODE_NONE: return "(none)"; + case WESTON_EOTF_MODE_SDR: return "SDR"; + case WESTON_EOTF_MODE_TRADITIONAL_HDR: return "traditional gamma HDR"; + case WESTON_EOTF_MODE_ST2084: return "ST2084"; + case WESTON_EOTF_MODE_HLG: return "HLG"; + } + return "???"; +} diff --git a/libweston/color.h b/libweston/color.h index 4667fcad..4db42e71 100644 --- a/libweston/color.h +++ b/libweston/color.h @@ -379,4 +379,7 @@ weston_color_manager_noop_create(struct weston_compositor *compositor); struct weston_color_manager * weston_color_manager_create(struct weston_compositor *compositor); +const char * +weston_eotf_mode_to_str(enum weston_eotf_mode e); + #endif /* WESTON_COLOR_H */ diff --git a/libweston/compositor.c b/libweston/compositor.c index 50598ef3..b7944b84 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -5437,6 +5437,7 @@ weston_head_init(struct weston_head *head, const char *name) wl_list_init(&head->resource_list); wl_list_init(&head->xdg_output_resource_list); head->name = strdup(name); + head->supported_eotf_mask = WESTON_EOTF_MODE_SDR; head->current_protection = WESTON_HDCP_DISABLE; } @@ -5962,6 +5963,31 @@ weston_head_set_connection_status(struct weston_head *head, bool connected) weston_head_set_device_changed(head); } +/** Store the set of supported EOTF modes + * + * \param head The head to modify. + * \param eotf_mask A bit mask with the possible bits or'ed together from + * enum weston_eotf_mode. + * + * This may set the device_changed flag. + * + * \ingroup head + * \internal + */ +WL_EXPORT void +weston_head_set_supported_eotf_mask(struct weston_head *head, + uint32_t eotf_mask) +{ + assert((eotf_mask & ~WESTON_EOTF_MODE_ALL_MASK) == 0); + + if (head->supported_eotf_mask == eotf_mask) + return; + + head->supported_eotf_mask = eotf_mask; + + weston_head_set_device_changed(head); +} + static void weston_output_compute_protection(struct weston_output *output) { @@ -6714,6 +6740,50 @@ weston_output_set_color_profile(struct weston_output *output, return true; } +/** Set EOTF mode on an output + * + * \param output The output to modify, must be in disabled state. + * \param eotf_mode The EOTF mode to set. + * + * Setting the output EOTF mode is used for turning HDR on/off. There are + * multiple modes for HDR on, see enum weston_eotf_mode. This is the high level + * choice on how to drive a video sink (monitor), either in the traditional + * SDR mode or in one of the HDR modes. + * + * After attaching heads to an output, you can find out the possibly supported + * EOTF modes with weston_output_get_supported_eotf_modes(). + * + * This function does not check whether the given eotf_mode is actually + * supported on the output. Enabling an output with an unsupported EOTF mode + * has undefined visual results. + * + * The initial EOTF mode is SDR. + * + * \ingroup output + */ +WL_EXPORT void +weston_output_set_eotf_mode(struct weston_output *output, + enum weston_eotf_mode eotf_mode) +{ + assert(!output->enabled); + + output->eotf_mode = eotf_mode; +} + +/** Get EOTF mode of an output + * + * \param output The output to query. + * \return The EOTF mode. + * + * \sa weston_output_set_eotf_mode + * \ingroup output + */ +WL_EXPORT enum weston_eotf_mode +weston_output_get_eotf_mode(const struct weston_output *output) +{ + return output->eotf_mode; +} + /** Initializes a weston_output object with enough data so ** an output can be configured. * @@ -6741,6 +6811,7 @@ weston_output_init(struct weston_output *output, wl_list_init(&output->link); wl_signal_init(&output->user_destroy_signal); output->enabled = false; + output->eotf_mode = WESTON_EOTF_MODE_SDR; output->desired_protection = WESTON_HDCP_DISABLE; output->allow_protection = true; @@ -6903,6 +6974,9 @@ weston_output_enable(struct weston_output *output) wl_list_init(&output->paint_node_list); wl_list_init(&output->paint_node_z_order_list); + weston_log("Output '%s' attempts EOTF mode: %s\n", output->name, + weston_eotf_mode_to_str(output->eotf_mode)); + if (!weston_output_set_color_transforms(output)) return -1; @@ -7222,6 +7296,34 @@ weston_output_allow_protection(struct weston_output *output, output->allow_protection = allow_protection; } +/** Get supported EOTF modes as a bit mask + * + * \param output The output to query. + * \return A bit mask with values from enum weston_eotf_mode or'ed together. + * + * Returns the bit mask of the EOTF modes that all the currently attached + * heads claim to support. Adding or removing heads may change the result. + * An output can be queried regrdless of whether it is enabled or disabled. + * + * If no heads are attached, no EOTF modes are deemed supported. + * + * \ingroup output + */ +WL_EXPORT uint32_t +weston_output_get_supported_eotf_modes(struct weston_output *output) +{ + uint32_t eotf_modes = WESTON_EOTF_MODE_ALL_MASK; + struct weston_head *head; + + if (wl_list_empty(&output->head_list)) + return WESTON_EOTF_MODE_NONE; + + wl_list_for_each(head, &output->head_list, output_link) + eotf_modes = eotf_modes & head->supported_eotf_mask; + + return eotf_modes; +} + static void xdg_output_unlist(struct wl_resource *resource) {