output: add color_format command

Allow configuring the output color format (RGB/YPbPr) via the
output config. Exposes the value in IPC JSON output.
This commit is contained in:
Igor Deordiev 2026-05-11 16:32:07 +07:00 committed by sourenaraya
parent 0bf8731114
commit 101b75fdc2
8 changed files with 63 additions and 0 deletions

View file

@ -286,6 +286,7 @@ sway_cmd input_cmd_xkb_variant;
sway_cmd output_cmd_adaptive_sync;
sway_cmd output_cmd_allow_tearing;
sway_cmd output_cmd_background;
sway_cmd output_cmd_color_format;
sway_cmd output_cmd_color_profile;
sway_cmd output_cmd_disable;
sway_cmd output_cmd_dpms;

View file

@ -8,6 +8,7 @@
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/util/box.h>
#include <wlr/render/color.h>
#include <wlr/types/wlr_output.h>
#include <xkbcommon/xkbcommon.h>
#include <xf86drmMode.h>
#include "../include/config.h"
@ -294,6 +295,7 @@ struct output_config {
int max_render_time; // In milliseconds
int adaptive_sync;
enum render_bit_depth render_bit_depth;
enum wlr_output_color_format color_format;
enum color_profile color_profile;
struct wlr_color_transform *color_transform;
int allow_tearing;

View file

@ -11,6 +11,7 @@ static const struct cmd_handler output_handlers[] = {
{ "allow_tearing", output_cmd_allow_tearing },
{ "background", output_cmd_background },
{ "bg", output_cmd_background },
{ "color_format", output_cmd_color_format },
{ "color_profile", output_cmd_color_profile },
{ "disable", output_cmd_disable },
{ "dpms", output_cmd_dpms },

View file

@ -0,0 +1,36 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
struct cmd_results *output_cmd_color_format(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing color format argument.");
}
if (strcmp(*argv, "auto") == 0) {
config->handler_context.output_config->color_format =
WLR_OUTPUT_COLOR_FORMAT_AUTO;
} else if (strcmp(*argv, "rgb") == 0) {
config->handler_context.output_config->color_format =
WLR_OUTPUT_COLOR_FORMAT_RGB444;
} else if (strcmp(*argv, "yuv444") == 0) {
config->handler_context.output_config->color_format =
WLR_OUTPUT_COLOR_FORMAT_YCBCR444;
} else if (strcmp(*argv, "yuv422") == 0) {
config->handler_context.output_config->color_format =
WLR_OUTPUT_COLOR_FORMAT_YCBCR422;
} else if (strcmp(*argv, "yuv420") == 0) {
config->handler_context.output_config->color_format =
WLR_OUTPUT_COLOR_FORMAT_YCBCR420;
} else {
return cmd_results_new(CMD_INVALID,
"Invalid color format. Must be a value in (auto|rgb|yuv444|yuv422|yuv420).");
}
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
return NULL;
}

View file

@ -75,6 +75,7 @@ struct output_config *new_output_config(const char *name) {
oc->max_render_time = -1;
oc->adaptive_sync = -1;
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
oc->color_format = WLR_OUTPUT_COLOR_FORMAT_AUTO;
oc->color_profile = COLOR_PROFILE_DEFAULT;
oc->color_transform = NULL;
oc->power = -1;
@ -130,6 +131,9 @@ static void supersede_output_config(struct output_config *dst, struct output_con
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
}
if (src->color_format != WLR_OUTPUT_COLOR_FORMAT_AUTO) {
dst->color_format = WLR_OUTPUT_COLOR_FORMAT_AUTO;
}
if (src->color_profile != COLOR_PROFILE_DEFAULT) {
if (dst->color_transform) {
wlr_color_transform_unref(dst->color_transform);
@ -207,6 +211,9 @@ static void merge_output_config(struct output_config *dst, struct output_config
if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
dst->render_bit_depth = src->render_bit_depth;
}
if (src->color_format != WLR_OUTPUT_COLOR_FORMAT_AUTO) {
dst->color_format = src->color_format;
}
if (src->color_profile != COLOR_PROFILE_DEFAULT) {
if (src->color_transform) {
wlr_color_transform_ref(src->color_transform);
@ -553,6 +560,9 @@ static void queue_output_config(struct output_config *oc,
} else {
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
}
if (oc && oc->color_format != WLR_OUTPUT_COLOR_FORMAT_AUTO) {
wlr_output_state_set_color_format(pending, oc->color_format);
}
bool hdr = oc && oc->hdr == 1;
bool color_profile = oc && (oc->color_transform != NULL

View file

@ -628,6 +628,7 @@ static struct output_config *output_config_for_config_head(
oc->transform = config_head->state.transform;
oc->scale = config_head->state.scale;
oc->adaptive_sync = config_head->state.adaptive_sync_enabled;
oc->color_format = config_head->state.color_format;
return oc;
}

View file

@ -410,6 +410,17 @@ static void ipc_json_describe_enabled_output(struct sway_output *output,
json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
json_object_object_add(object, "allow_tearing", json_object_new_boolean(output->allow_tearing));
json_object_object_add(object, "hdr", json_object_new_boolean(output->hdr));
const char *color_format_str = NULL;
switch (wlr_output->color_format) {
case WLR_OUTPUT_COLOR_FORMAT_AUTO: color_format_str = "auto"; break;
case WLR_OUTPUT_COLOR_FORMAT_RGB444: color_format_str = "rgb"; break;
case WLR_OUTPUT_COLOR_FORMAT_YCBCR444: color_format_str = "yuv444"; break;
case WLR_OUTPUT_COLOR_FORMAT_YCBCR422: color_format_str = "yuv422"; break;
case WLR_OUTPUT_COLOR_FORMAT_YCBCR420: color_format_str = "yuv420"; break;
}
json_object_object_add(object, "color_format",
json_object_new_string(color_format_str));
}
json_object *ipc_json_describe_disabled_output(struct sway_output *output) {

View file

@ -192,6 +192,7 @@ sway_sources = files(
'commands/output/adaptive_sync.c',
'commands/output/allow_tearing.c',
'commands/output/background.c',
'commands/output/color_format.c',
'commands/output/disable.c',
'commands/output/dpms.c',
'commands/output/enable.c',