From 101b75fdc2eea89ae881b5ff53373823f5aba742 Mon Sep 17 00:00:00 2001 From: Igor Deordiev Date: Mon, 11 May 2026 16:32:07 +0700 Subject: [PATCH] output: add color_format command Allow configuring the output color format (RGB/YPbPr) via the output config. Exposes the value in IPC JSON output. --- include/sway/commands.h | 1 + include/sway/config.h | 2 ++ sway/commands/output.c | 1 + sway/commands/output/color_format.c | 36 +++++++++++++++++++++++++++++ sway/config/output.c | 10 ++++++++ sway/desktop/output.c | 1 + sway/ipc-json.c | 11 +++++++++ sway/meson.build | 1 + 8 files changed, 63 insertions(+) create mode 100644 sway/commands/output/color_format.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 389c382eb..006679ff8 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -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; diff --git a/include/sway/config.h b/include/sway/config.h index 16b822fea..6a9ab8752 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #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; diff --git a/sway/commands/output.c b/sway/commands/output.c index afff23f6a..3ff169c64 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -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 }, diff --git a/sway/commands/output/color_format.c b/sway/commands/output/color_format.c new file mode 100644 index 000000000..e7d6bbfdd --- /dev/null +++ b/sway/commands/output/color_format.c @@ -0,0 +1,36 @@ +#include +#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; +} diff --git a/sway/config/output.c b/sway/config/output.c index 6d6afdc25..1fefb2c52 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -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 diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 12dc9cc7a..03c368baa 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -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; } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 3b69ad384..2991dcd82 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -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) { diff --git a/sway/meson.build b/sway/meson.build index cb03a4d28..b88e4eba4 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -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',