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 <derek.foreman@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
This commit is contained in:
Derek Foreman 2025-10-08 21:40:29 +03:00 committed by Marius Vlad
parent 67f8d9d6a6
commit 4615d2a779
8 changed files with 173 additions and 0 deletions

View file

@ -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,

View file

@ -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
*/

View file

@ -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);

View file

@ -30,6 +30,7 @@
#include <assert.h>
#include <string.h>
#include <math.h>
#include <shared/weston-assert.h>
#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;
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

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