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) {