Merge branch 'output_color_format' into 'master'

Draft: output: add color_format state field

See merge request wlroots/wlroots!5364
This commit is contained in:
Igor Deordiev 2026-06-11 09:17:41 +00:00
commit 66df6f3a4d
11 changed files with 135 additions and 7 deletions

View file

@ -401,6 +401,7 @@ bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool mo
state->vrr_enabled = vrr_enabled;
state->colorspace = colorspace;
state->hdr_output_metadata = hdr_output_metadata;
state->color_format = state->base->color_format;
return true;
}
@ -567,6 +568,10 @@ static void atomic_connector_add(struct atomic *atom,
if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) {
atomic_add(atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb));
}
if (modeset && conn->props.color_format != 0 &&
state->base->committed & WLR_OUTPUT_STATE_COLOR_FORMAT) {
atomic_add(atom, conn->id, conn->props.color_format, state->color_format);
}
if (conn->props.colorspace != 0) {
atomic_add(atom, conn->id, conn->props.colorspace, state->colorspace);
}

View file

@ -44,7 +44,8 @@ static const uint32_t COMMIT_OUTPUT_STATE =
WLR_OUTPUT_STATE_SIGNAL_TIMELINE |
WLR_OUTPUT_STATE_COLOR_TRANSFORM |
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION |
WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
WLR_OUTPUT_STATE_COLOR_REPRESENTATION |
WLR_OUTPUT_STATE_COLOR_FORMAT;
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;

View file

@ -27,6 +27,7 @@ static const struct prop_info connector_info[] = {
{ "EDID", INDEX(edid) },
{ "HDR_OUTPUT_METADATA", INDEX(hdr_output_metadata) },
{ "PATH", INDEX(path) },
{ "color format", INDEX(color_format) },
{ "content type", INDEX(content_type) },
{ "link-status", INDEX(link_status) },
{ "max bpc", INDEX(max_bpc) },

View file

@ -162,6 +162,7 @@ struct wlr_drm_connector_state {
uint32_t fb_damage_clips;
int primary_in_fence_fd;
bool vrr_enabled;
uint32_t color_format;
uint32_t colorspace;
uint32_t hdr_output_metadata;
};

View file

@ -22,6 +22,7 @@ struct wlr_drm_connector_props {
uint32_t panel_orientation; // not guaranteed to exist
uint32_t content_type; // not guaranteed to exist
uint32_t max_bpc; // not guaranteed to exist
uint32_t color_format; // not guaranteed to exist
// atomic-modesetting only

View file

@ -78,6 +78,21 @@ enum wlr_output_state_field {
WLR_OUTPUT_STATE_COLOR_TRANSFORM = 1 << 12,
WLR_OUTPUT_STATE_IMAGE_DESCRIPTION = 1 << 13,
WLR_OUTPUT_STATE_COLOR_REPRESENTATION = 1 << 14,
WLR_OUTPUT_STATE_COLOR_FORMAT = 1 << 15,
};
/**
* DRM color format for output connectors.
*
* These values match enum drm_connector_color_format in the kernel.
* AUTO (0) is the default and lets the driver pick.
*/
enum wlr_output_color_format {
WLR_OUTPUT_COLOR_FORMAT_AUTO = 0,
WLR_OUTPUT_COLOR_FORMAT_RGB444,
WLR_OUTPUT_COLOR_FORMAT_YCBCR444,
WLR_OUTPUT_COLOR_FORMAT_YCBCR422,
WLR_OUTPUT_COLOR_FORMAT_YCBCR420,
};
enum wlr_output_state_mode_type {
@ -165,6 +180,8 @@ struct wlr_output_state {
struct wlr_color_transform *color_transform;
struct wlr_output_image_description *image_description;
uint32_t color_format; // enum wlr_output_color_format
};
struct wlr_output_impl;
@ -210,6 +227,7 @@ struct wlr_output {
enum wl_output_transform transform;
enum wlr_output_adaptive_sync_status adaptive_sync_status;
uint32_t render_format;
enum wlr_output_color_format color_format;
enum wlr_color_encoding color_encoding;
enum wlr_color_range color_range;
const struct wlr_output_image_description *image_description;
@ -641,6 +659,20 @@ void wlr_output_state_set_color_encoding_and_range(
struct wlr_output_state *state,
enum wlr_color_encoding encoding, enum wlr_color_range range);
/**
* Sets the color format for an output. The color format determines the color
* encoding sent to the display (RGB, YCbCr 4:4:4, YCbCr 4:2:2, YCbCr 4:2:0).
*
* The default value is WLR_OUTPUT_COLOR_FORMAT_AUTO.
*
* Not all connectors support all color formats. If the connector doesn't
* support the "color format" DRM property, this setting is ignored.
*
* This state will be applied once wlr_output_commit_state() is called.
*/
void wlr_output_state_set_color_format(struct wlr_output_state *state,
enum wlr_output_color_format color_format);
/**
* Copies the output state from src to dst. It is safe to then
* wlr_output_state_finish() src and have dst still be valid.

View file

@ -59,6 +59,7 @@ struct wlr_output_head_v1_state {
enum wl_output_transform transform;
float scale;
bool adaptive_sync_enabled;
enum wlr_output_color_format color_format;
};
struct wlr_output_head_v1 {

View file

@ -39,7 +39,7 @@
interface version number is reset.
</description>
<interface name="zwlr_output_manager_v1" version="4">
<interface name="zwlr_output_manager_v1" version="5">
<description summary="output device configuration manager">
This interface is a manager that allows reading and writing the current
output device configuration.
@ -125,7 +125,7 @@
</event>
</interface>
<interface name="zwlr_output_head_v1" version="4">
<interface name="zwlr_output_head_v1" version="5">
<description summary="output device">
A head is an output device. The difference between a wl_output object and
a head is that heads are advertised even if they are turned off. A head
@ -364,6 +364,28 @@
</description>
<arg name="state" type="uint" enum="adaptive_sync_state"/>
</event>
<!-- Version 5 additions -->
<enum name="color_format" since="5">
<description summary="color format for the output">
These values correspond to the DRM connector color format property.
The compositor may not support all formats on all connectors.
</description>
<entry name="auto" value="0" summary="compositor/driver picks"/>
<entry name="rgb" value="1" summary="RGB output"/>
<entry name="ycbcr444" value="2" summary="YCbCr 4:4:4"/>
<entry name="ycbcr422" value="3" summary="YCbCr 4:2:2"/>
<entry name="ycbcr420" value="4" summary="YCbCr 4:2:0"/>
</enum>
<event name="color_format" since="5">
<description summary="current color format">
This event describes the color format currently used by the head.
The color format determines the color encoding sent to the display.
</description>
<arg name="format" type="uint" enum="color_format"/>
</event>
</interface>
<interface name="zwlr_output_mode_v1" version="3">
@ -421,7 +443,7 @@
</request>
</interface>
<interface name="zwlr_output_configuration_v1" version="4">
<interface name="zwlr_output_configuration_v1" version="5">
<description summary="output configuration">
This object is used by the client to describe a full output configuration.
@ -539,7 +561,7 @@
</request>
</interface>
<interface name="zwlr_output_configuration_head_v1" version="4">
<interface name="zwlr_output_configuration_head_v1" version="5">
<description summary="head configuration">
This object is used by the client to update a single head's configuration.
@ -554,6 +576,8 @@
<entry name="invalid_scale" value="5" summary="scale negative or zero"/>
<entry name="invalid_adaptive_sync_state" value="6" since="4"
summary="invalid enum value used in the set_adaptive_sync request"/>
<entry name="invalid_color_format" value="7" since="5"
summary="invalid enum value used in the set_color_format request"/>
</enum>
<request name="set_mode">
@ -607,5 +631,19 @@
</description>
<arg name="state" type="uint" enum="zwlr_output_head_v1.adaptive_sync_state"/>
</request>
<!-- Version 5 additions -->
<request name="set_color_format" since="5">
<description summary="set the color format">
This request sets the color format for the output. The color format
determines the color encoding sent to the display (RGB, YCbCr 4:4:4,
YCbCr 4:2:2, YCbCr 4:2:0).
If the connector does not support the color format property, the
compositor should ignore this request.
</description>
<arg name="format" type="uint" enum="zwlr_output_head_v1.color_format"/>
</request>
</interface>
</protocol>

View file

@ -216,6 +216,10 @@ static void output_apply_state(struct wlr_output *output,
output->render_format = state->render_format;
}
if (state->committed & WLR_OUTPUT_STATE_COLOR_FORMAT) {
output->color_format = state->color_format;
}
if (state->committed & WLR_OUTPUT_STATE_SUBPIXEL) {
output->subpixel = state->subpixel;
}
@ -357,6 +361,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend,
.impl = impl,
.event_loop = event_loop,
.render_format = DRM_FORMAT_XRGB8888,
.color_format = WLR_OUTPUT_COLOR_FORMAT_AUTO,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.scale = 1,
.commit_seq = 0,
@ -590,6 +595,10 @@ static uint32_t output_compare_state(struct wlr_output *output,
output->color_range == state->color_range) {
fields |= WLR_OUTPUT_STATE_COLOR_REPRESENTATION;
}
if ((state->committed & WLR_OUTPUT_STATE_COLOR_FORMAT) &&
output->color_format == state->color_format) {
fields |= WLR_OUTPUT_STATE_COLOR_FORMAT;
}
return fields;
}

View file

@ -97,6 +97,12 @@ void wlr_output_state_set_layers(struct wlr_output_state *state,
state->layers_len = layers_len;
}
void wlr_output_state_set_color_format(struct wlr_output_state *state,
enum wlr_output_color_format color_format) {
state->committed |= WLR_OUTPUT_STATE_COLOR_FORMAT;
state->color_format = color_format;
}
void wlr_output_state_set_wait_timeline(struct wlr_output_state *state,
struct wlr_drm_syncobj_timeline *timeline, uint64_t src_point) {
state->committed |= WLR_OUTPUT_STATE_WAIT_TIMELINE;

View file

@ -6,7 +6,7 @@
#include <wlr/util/log.h>
#include "wlr-output-management-unstable-v1-protocol.h"
#define OUTPUT_MANAGER_VERSION 4
#define OUTPUT_MANAGER_VERSION 5
enum {
HEAD_STATE_ENABLED = 1 << 0,
@ -15,11 +15,12 @@ enum {
HEAD_STATE_TRANSFORM = 1 << 3,
HEAD_STATE_SCALE = 1 << 4,
HEAD_STATE_ADAPTIVE_SYNC = 1 << 5,
HEAD_STATE_COLOR_FORMAT = 1 << 6,
};
static const uint32_t HEAD_STATE_ALL = HEAD_STATE_ENABLED | HEAD_STATE_MODE |
HEAD_STATE_POSITION | HEAD_STATE_TRANSFORM | HEAD_STATE_SCALE |
HEAD_STATE_ADAPTIVE_SYNC;
HEAD_STATE_ADAPTIVE_SYNC | HEAD_STATE_COLOR_FORMAT;
static const struct zwlr_output_head_v1_interface head_impl;
@ -162,6 +163,7 @@ struct wlr_output_configuration_head_v1 *
config_head->state.scale = output->scale;
config_head->state.adaptive_sync_enabled =
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
config_head->state.color_format = output->color_format;
return config_head;
}
@ -307,6 +309,24 @@ static void config_head_handle_set_adaptive_sync(struct wl_client *client,
}
}
static void config_head_handle_set_color_format(struct wl_client *client,
struct wl_resource *config_head_resource, uint32_t format) {
struct wlr_output_configuration_head_v1 *config_head =
config_head_from_resource(config_head_resource);
if (config_head == NULL) {
return;
}
if (format > ZWLR_OUTPUT_HEAD_V1_COLOR_FORMAT_YCBCR420) {
wl_resource_post_error(config_head_resource,
ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_COLOR_FORMAT,
"client requested invalid color format %u", format);
return;
}
config_head->state.color_format = format;
}
static const struct zwlr_output_configuration_head_v1_interface config_head_impl = {
.set_mode = config_head_handle_set_mode,
.set_custom_mode = config_head_handle_set_custom_mode,
@ -314,6 +334,7 @@ static const struct zwlr_output_configuration_head_v1_interface config_head_impl
.set_transform = config_head_handle_set_transform,
.set_scale = config_head_handle_set_scale,
.set_adaptive_sync = config_head_handle_set_adaptive_sync,
.set_color_format = config_head_handle_set_color_format,
};
static void config_head_handle_resource_destroy(struct wl_resource *resource) {
@ -815,6 +836,13 @@ static void head_send_state(struct wlr_output_head_v1 *head,
ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED);
}
}
if ((state & HEAD_STATE_COLOR_FORMAT) &&
wl_resource_get_version(head_resource) >=
ZWLR_OUTPUT_HEAD_V1_COLOR_FORMAT_SINCE_VERSION) {
zwlr_output_head_v1_send_color_format(head_resource,
head->state.color_format);
}
}
static void head_handle_resource_destroy(struct wl_resource *resource) {
@ -911,6 +939,9 @@ static bool manager_update_head(struct wlr_output_manager_v1 *manager,
if (current->adaptive_sync_enabled != next->adaptive_sync_enabled) {
state |= HEAD_STATE_ADAPTIVE_SYNC;
}
if (current->color_format != next->color_format) {
state |= HEAD_STATE_COLOR_FORMAT;
}
// If a mode was added to wlr_output.modes we need to add the new mode
// to the wlr_output_head
@ -1032,6 +1063,8 @@ void wlr_output_head_v1_state_apply(
wlr_output_state_set_transform(output_state, head_state->transform);
wlr_output_state_set_adaptive_sync_enabled(output_state,
head_state->adaptive_sync_enabled);
wlr_output_state_set_color_format(output_state,
head_state->color_format);
}
struct wlr_backend_output_state *wlr_output_configuration_v1_build_state(