From 4615d2a7792444a1ea3f75b9857dabe0dbd8b1ca Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Wed, 8 Oct 2025 21:40:29 +0300 Subject: [PATCH] backend-drm: Add support for the DRM connector property 'color format' This is the last part to support the 'color format' DRM connector. Signed-off-by: Derek Foreman Signed-off-by: Nicolas Frattaroli Signed-off-by: Marius Vlad --- libweston/backend-drm/drm-internal.h | 5 +++ libweston/backend-drm/drm-kms-enums.h | 10 ++++++ libweston/backend-drm/drm.c | 11 +++++++ libweston/backend-drm/kms-color.c | 28 ++++++++++++++++ libweston/backend-drm/kms.c | 46 +++++++++++++++++++++++++++ libweston/backend-drm/modes.c | 44 +++++++++++++++++++++++++ libweston/backend.h | 3 ++ libweston/compositor.c | 26 +++++++++++++++ 8 files changed, 173 insertions(+) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 90ca71686..8266f6d52 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -705,6 +705,8 @@ struct drm_output { bool reused_state; bool force_rebuild_state; + + enum wdrm_color_format connector_color_format; }; void @@ -938,6 +940,9 @@ drm_output_ensure_hdr_output_metadata_blob(struct drm_output *output); enum wdrm_colorspace wdrm_colorspace_from_output(struct weston_output *output); +enum wdrm_color_format +wdrm_color_format_from_output(struct weston_output *output); + #ifdef BUILD_DRM_GBM extern struct drm_fb * drm_fb_get_from_paint_node(struct drm_output_state *state, diff --git a/libweston/backend-drm/drm-kms-enums.h b/libweston/backend-drm/drm-kms-enums.h index b7b886766..60c1f0fdd 100644 --- a/libweston/backend-drm/drm-kms-enums.h +++ b/libweston/backend-drm/drm-kms-enums.h @@ -205,6 +205,7 @@ enum wdrm_connector_property { WDRM_CONNECTOR_RIGHT_MARGIN, WDRM_CONNECTOR_TOP_MARGIN, WDRM_CONNECTOR_BOTTOM_MARGIN, + WDRM_CONNECTOR_COLOR_FORMAT, WDRM_CONNECTOR__COUNT }; @@ -273,6 +274,15 @@ enum wdrm_underscan { WDRM_UNDERSCAN__COUNT }; +enum wdrm_color_format { + WDRM_COLOR_FORMAT_RGB, + WDRM_COLOR_FORMAT_YUV422, + WDRM_COLOR_FORMAT_YUV444, + WDRM_COLOR_FORMAT_YUV420, + WDRM_COLOR_FORMAT_AUTO, + WDRM_COLOR_FORMAT__COUNT +}; + /** * List of properties attached to DRM CRTCs */ diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index b1887f610..dd5d1be91 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -2863,6 +2863,10 @@ drm_output_enable(struct weston_output *base) if (output->connector_colorspace == WDRM_COLORSPACE__COUNT) return -1; + output->connector_color_format = wdrm_color_format_from_output(&output->base); + if (output->connector_color_format == WDRM_COLOR_FORMAT__COUNT) + return -1; + ret = drm_output_attach_crtc(output); if (ret < 0) return -1; @@ -3245,6 +3249,13 @@ drm_head_log_info(struct drm_head *head, const char *msg) head->base.underscan_vborder_max); } + str = weston_color_format_mask_to_str(head->base.supported_color_format_mask); + if (str) { + weston_log_continue(STAMP_SPACE + "Supported color formats: %s\n", + str); + } + free(str); } else { weston_log("DRM: head '%s' %s, connector %d is disconnected.\n", head->base.name, msg, head->connector.connector_id); diff --git a/libweston/backend-drm/kms-color.c b/libweston/backend-drm/kms-color.c index ee96c963c..bb58e7a7b 100644 --- a/libweston/backend-drm/kms-color.c +++ b/libweston/backend-drm/kms-color.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "drm-internal.h" @@ -193,3 +194,30 @@ wdrm_colorspace_from_output(struct weston_output *output) return cm->wdrm; } + +enum wdrm_color_format +wdrm_color_format_from_output(struct weston_output *output) +{ + enum weston_color_format color_format = output->color_format; + + if (!color_format) + return WDRM_COLOR_FORMAT_AUTO; + + weston_assert_true(output->compositor, + weston_output_get_supported_color_formats(output) & color_format); + + switch (color_format) { + case WESTON_COLOR_FORMAT_AUTO: + return WDRM_COLOR_FORMAT_AUTO; + case WESTON_COLOR_FORMAT_RGB: + return WDRM_COLOR_FORMAT_RGB; + case WESTON_COLOR_FORMAT_YUV444: + return WDRM_COLOR_FORMAT_YUV444; + case WESTON_COLOR_FORMAT_YUV422: + return WDRM_COLOR_FORMAT_YUV422; + case WESTON_COLOR_FORMAT_YUV420: + return WDRM_COLOR_FORMAT_YUV420; + default: + return WDRM_COLOR_FORMAT__COUNT; + } +} diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index e4e43ca1d..cb6872c90 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -283,6 +283,14 @@ struct drm_property_enum_info underscan_enums[] = { [WDRM_UNDERSCAN_AUTO] = { .name = "auto", }, }; +struct drm_property_enum_info color_format_enums[] = { + [WDRM_COLOR_FORMAT_AUTO] = { .name = "AUTO", }, + [WDRM_COLOR_FORMAT_RGB] = { .name = "RGB", }, + [WDRM_COLOR_FORMAT_YUV422] = { .name = "YUV 4:2:2", }, + [WDRM_COLOR_FORMAT_YUV444] = { .name = "YUV 4:4:4", }, + [WDRM_COLOR_FORMAT_YUV420] = { .name = "YUV 4:2:0", }, +}; + const struct drm_property_info connector_props[] = { [WDRM_CONNECTOR_EDID] = { .name = "EDID" }, [WDRM_CONNECTOR_DPMS] = { @@ -350,6 +358,11 @@ const struct drm_property_info connector_props[] = { [WDRM_CONNECTOR_BOTTOM_MARGIN] = { .name = "bottom margin", }, + [WDRM_CONNECTOR_COLOR_FORMAT] = { + .name = "color format", + .enum_values = color_format_enums, + .num_enum_values = WDRM_COLOR_FORMAT__COUNT, + }, }; const struct drm_property_info crtc_props[] = { @@ -1479,6 +1492,32 @@ drm_plane_set_color_encoding(struct drm_plane *plane, color_encoding); } +static int +drm_connector_set_color_format(struct drm_connector *connector, + enum wdrm_color_format color_format, + drmModeAtomicReq *req) +{ + const struct drm_property_info *info; + const struct drm_property_enum_info *enum_info; + + assert(color_format >= 0); + assert(color_format < WDRM_COLOR_FORMAT__COUNT); + + if (!drm_connector_has_prop(connector, WDRM_CONNECTOR_COLOR_FORMAT)) { + if (color_format == WDRM_COLOR_FORMAT_AUTO) + return 0; + + return -1; + } + + info = &connector->props[WDRM_CONNECTOR_COLOR_FORMAT]; + enum_info = &info->enum_values[color_format]; + assert(enum_info->valid); + + return connector_add_prop(req, connector, WDRM_CONNECTOR_COLOR_FORMAT, + enum_info->value); +} + static int drm_plane_set_color_range(struct drm_plane *plane, enum wdrm_plane_color_range color_range, @@ -1789,6 +1828,8 @@ drm_output_apply_state_atomic(struct drm_output_state *state, ret |= drm_connector_set_colorspace(&head->connector, output->connector_colorspace, req); ret |= drm_connector_set_underscan(&head->connector, output, req); + ret |= drm_connector_set_color_format(&head->connector, + output->connector_color_format, req); } if (ret != 0) { @@ -2005,6 +2046,11 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state, wl_list_for_each(output_state, &pending_state->output_list, link) { if (output_state->output->is_virtual) continue; + + if (output_state->output->connector_color_format != + wdrm_color_format_from_output(&output_state->output->base)) + weston_assert_true(b->compositor, output_state->output->base.enabled); + if (mode == DRM_STATE_APPLY_SYNC) assert(output_state->dpms == WESTON_DPMS_OFF); may_tear &= output_state->tear; diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c index f2743d3ee..8243c1540 100644 --- a/libweston/backend-drm/modes.c +++ b/libweston/backend-drm/modes.c @@ -553,6 +553,47 @@ drm_head_get_underscan_caps(const struct drm_head *head, *hborder_max_out = hborder_max; } +static enum weston_color_format +color_format_from_wdrm_color_format(enum wdrm_color_format format) +{ + switch (format) { + case WDRM_COLOR_FORMAT_AUTO: + return WESTON_COLOR_FORMAT_AUTO; + case WDRM_COLOR_FORMAT_RGB: + return WESTON_COLOR_FORMAT_RGB; + case WDRM_COLOR_FORMAT_YUV444: + return WESTON_COLOR_FORMAT_YUV444; + case WDRM_COLOR_FORMAT_YUV422: + return WESTON_COLOR_FORMAT_YUV422; + case WDRM_COLOR_FORMAT_YUV420: + return WESTON_COLOR_FORMAT_YUV420; + default: + return WESTON_COLOR_FORMAT_AUTO; + } +} + +static uint32_t +drm_head_get_kms_color_formats(const struct drm_head *head) +{ + const struct drm_property_info *info; + uint32_t color_formats = WESTON_COLOR_FORMAT_AUTO; + unsigned i; + + /* Cannot bother implementing without atomic */ + if (!head->connector.device->atomic_modeset) + return color_formats; + + info = &head->connector.props[WDRM_CONNECTOR_COLOR_FORMAT]; + if (info->prop_id == 0) + return color_formats; + + for (i = 0; i < WDRM_COLOR_FORMAT__COUNT; i++) + if (info->enum_values[i].valid) + color_formats |= color_format_from_wdrm_color_format(i); + + return color_formats; +} + static uint32_t drm_refresh_rate_mHz(const drmModeModeInfo *info) { @@ -789,6 +830,9 @@ update_head_from_connector(struct drm_head *head) drm_head_get_underscan_caps(head, &hborder_max, &vborder_max); weston_head_set_supported_underscan(&head->base, hborder_max, vborder_max); + dhi.color_format_mask &= drm_head_get_kms_color_formats(head); + weston_head_set_supported_color_format_mask(&head->base, dhi.color_format_mask); + drm_head_info_fini(&dhi); } diff --git a/libweston/backend.h b/libweston/backend.h index 4671f98c8..bcaa1bc83 100644 --- a/libweston/backend.h +++ b/libweston/backend.h @@ -190,6 +190,9 @@ weston_head_set_supported_vrr_modes_mask(struct weston_head *head, void weston_head_set_supported_underscan(struct weston_head *head, uint32_t hborder, uint32_t vborder); +void +weston_head_set_supported_color_format_mask(struct weston_head *head, + uint32_t color_format_mask); /* weston_output */ void diff --git a/libweston/compositor.c b/libweston/compositor.c index a991371d9..73b5a5456 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -7223,6 +7223,32 @@ weston_head_set_supported_colorimetry_mask(struct weston_head *head, weston_head_set_device_changed(head); } +/** Store the set of supported color formats + * + * \param head The head to modify. + * \param color_format_mask A bit mask with the possible bits or'ed together + * from enum weston_color_format. + * + * This may set the device_changed flag. + * + * \ingroup head + * \internal + */ +WL_EXPORT void +weston_head_set_supported_color_format_mask(struct weston_head *head, + uint32_t color_format_mask) +{ + weston_assert_legal_bits(head->compositor, color_format_mask, + WESTON_COLOR_FORMAT_ALL_MASK); + + if (head->supported_color_format_mask == color_format_mask) + return; + + head->supported_color_format_mask = color_format_mask; + + weston_head_set_device_changed(head); +} + WL_EXPORT void weston_head_set_supported_vrr_modes_mask(struct weston_head *head, uint32_t vrr_mode_mask)