From c7d7d56f61f820989aa4ca6ee6267fe0bd31f5f6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 5 Jul 2025 13:25:51 +0200 Subject: [PATCH 1/4] ipc-json, swaymsg: indicate when adaptive sync is unsupported --- sway/ipc-json.c | 6 ++++++ swaymsg/main.c | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index d3adedd4e..6a0d462f6 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -318,6 +318,12 @@ static void ipc_json_describe_wlr_output(struct wlr_output *wlr_output, json_obj json_object_array_add(modes_array, mode_object); } json_object_object_add(object, "modes", modes_array); + + json_object *features_object = json_object_new_object(); + json_object_object_add(features_object, "adaptive_sync", + json_object_new_boolean(wlr_output->adaptive_sync_supported || + wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)); + json_object_object_add(object, "features", features_object); } static void ipc_json_describe_output(struct sway_output *output, diff --git a/swaymsg/main.c b/swaymsg/main.c index 6a9eb1987..9152b7942 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -210,6 +210,9 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(current_mode, "width", &width); json_object_object_get_ex(current_mode, "height", &height); json_object_object_get_ex(current_mode, "refresh", &refresh); + json_object *features, *features_adaptive_sync; + json_object_object_get_ex(o, "features", &features); + json_object_object_get_ex(features, "adaptive_sync", &features_adaptive_sync); if (json_object_get_boolean(non_desktop)) { printf( @@ -252,7 +255,9 @@ static void pretty_print_output(json_object *o) { printf(max_render_time_int == 0 ? "off\n" : "%d ms\n", max_render_time_int); printf(" Adaptive sync: %s\n", - json_object_get_string(adaptive_sync_status)); + json_object_get_boolean(features_adaptive_sync) ? + json_object_get_string(adaptive_sync_status) : + "unsupported"); printf(" Allow tearing: %s\n", json_object_get_boolean(allow_tearing) ? "yes" : "no"); From bac8c0f4d0a569ac9f63a2055bb8c886778dcf06 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 27 Jan 2025 21:00:54 +0100 Subject: [PATCH 2/4] Add support for HDR10 output --- include/sway/commands.h | 1 + include/sway/config.h | 3 +- include/sway/output.h | 2 + sway/commands/output.c | 1 + sway/commands/output/hdr.c | 37 +++++++++++++++ sway/config/output.c | 96 ++++++++++++++++++++++++++++++-------- sway/ipc-json.c | 2 +- sway/meson.build | 1 + sway/sway-ipc.7.scd | 3 ++ sway/sway-output.5.scd | 11 +++++ swaymsg/main.c | 5 +- 11 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 sway/commands/output/hdr.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 5210d3ba7..389c382eb 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -290,6 +290,7 @@ sway_cmd output_cmd_color_profile; sway_cmd output_cmd_disable; sway_cmd output_cmd_dpms; sway_cmd output_cmd_enable; +sway_cmd output_cmd_hdr; sway_cmd output_cmd_max_render_time; sway_cmd output_cmd_mode; sway_cmd output_cmd_modeline; diff --git a/include/sway/config.h b/include/sway/config.h index bb770c6f7..3c380933e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -261,7 +261,7 @@ enum scale_filter_mode { }; enum render_bit_depth { - RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 + RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 for SDR, 10 for HDR RENDER_BIT_DEPTH_6, RENDER_BIT_DEPTH_8, RENDER_BIT_DEPTH_10, @@ -291,6 +291,7 @@ struct output_config { bool set_color_transform; struct wlr_color_transform *color_transform; int allow_tearing; + int hdr; char *background; char *background_option; diff --git a/include/sway/output.h b/include/sway/output.h index 756a0ec22..06f8bac23 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -68,7 +68,9 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + bool allow_tearing; + bool hdr; }; struct sway_output_non_desktop { diff --git a/sway/commands/output.c b/sway/commands/output.c index 9d58413f2..afff23f6a 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -15,6 +15,7 @@ static const struct cmd_handler output_handlers[] = { { "disable", output_cmd_disable }, { "dpms", output_cmd_dpms }, { "enable", output_cmd_enable }, + { "hdr", output_cmd_hdr }, { "max_render_time", output_cmd_max_render_time }, { "mode", output_cmd_mode }, { "modeline", output_cmd_modeline }, diff --git a/sway/commands/output/hdr.c b/sway/commands/output/hdr.c new file mode 100644 index 000000000..26d202216 --- /dev/null +++ b/sway/commands/output/hdr.c @@ -0,0 +1,37 @@ +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "util.h" + +struct cmd_results *output_cmd_hdr(int argc, char **argv) { + if (!config->handler_context.output_config) { + return cmd_results_new(CMD_FAILURE, "Missing output config"); + } + if (argc == 0) { + return cmd_results_new(CMD_INVALID, "Missing hdr argument"); + } + + bool current = false; + if (strcasecmp(argv[0], "toggle") == 0) { + const char *oc_name = config->handler_context.output_config->name; + if (strcmp(oc_name, "*") == 0) { + return cmd_results_new(CMD_INVALID, + "Cannot apply toggle to all outputs"); + } + + struct sway_output *output = all_output_by_name_or_id(oc_name); + if (!output) { + return cmd_results_new(CMD_FAILURE, + "Cannot apply toggle to unknown output %s", oc_name); + } + + current = output->hdr; + } + + config->handler_context.output_config->hdr = parse_boolean(argv[0], current); + + 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 df80cab64..ab2cd2006 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -79,6 +79,7 @@ struct output_config *new_output_config(const char *name) { oc->color_transform = NULL; oc->power = -1; oc->allow_tearing = -1; + oc->hdr = -1; return oc; } @@ -154,6 +155,9 @@ static void supersede_output_config(struct output_config *dst, struct output_con if (src->allow_tearing != -1) { dst->allow_tearing = -1; } + if (src->hdr != -1) { + dst->hdr = -1; + } } // merge_output_config sets all fields in dst that were set in src @@ -229,6 +233,9 @@ static void merge_output_config(struct output_config *dst, struct output_config if (src->allow_tearing != -1) { dst->allow_tearing = src->allow_tearing; } + if (src->hdr != -1) { + dst->hdr = src->hdr; + } } void store_output_config(struct output_config *oc) { @@ -271,11 +278,11 @@ void store_output_config(struct output_config *oc) { sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " - "(max render time: %d) (allow tearing: %d)", + "(max render time: %d) (allow tearing: %d) (hdr: %d)", oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), oc->transform, oc->background, oc->background_option, oc->power, - oc->max_render_time, oc->allow_tearing); + oc->max_render_time, oc->allow_tearing, oc->hdr); // If the configuration was not merged into an existing configuration, add // it to the list. Otherwise we're done with it and can free it. @@ -341,6 +348,41 @@ static void set_modeline(struct wlr_output *output, #endif } +static void set_hdr(struct wlr_output *output, struct wlr_output_state *pending, bool enabled) { + enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020; + enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ; + if (enabled && !(output->supported_primaries & primaries)) { + sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: BT2020 primaries not supported by output", + output->name); + enabled = false; + } + if (enabled && !(output->supported_transfer_functions & WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) { + sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: PQ transfer function not supported by output", + output->name); + enabled = false; + } + if (enabled && !server.renderer->features.output_color_transform) { + sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: renderer doesn't support output color transforms", + output->name); + enabled = false; + } + + if (!enabled) { + if (output->supported_primaries != 0 || output->supported_transfer_functions != 0) { + sway_log(SWAY_DEBUG, "Disabling HDR on output %s", output->name); + wlr_output_state_set_image_description(pending, NULL); + } + return; + } + + sway_log(SWAY_DEBUG, "Enabling HDR on output %s", output->name); + const struct wlr_output_image_description image_desc = { + .primaries = primaries, + .transfer_function = tf, + }; + wlr_output_state_set_image_description(pending, &image_desc); +} + /* Some manufacturers hardcode the aspect-ratio of the output in the physical * size field. */ static bool phys_size_is_aspect_ratio(struct wlr_output *output) { @@ -415,6 +457,16 @@ static enum render_bit_depth bit_depth_from_format(uint32_t render_format) { return RENDER_BIT_DEPTH_DEFAULT; } +static enum render_bit_depth get_config_render_bit_depth(const struct output_config *oc) { + if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { + return oc->render_bit_depth; + } + if (oc && oc->hdr == 1) { + return RENDER_BIT_DEPTH_10; + } + return RENDER_BIT_DEPTH_8; +} + static bool render_format_is_bgr(uint32_t fmt) { return fmt == DRM_FORMAT_XBGR2101010 || fmt == DRM_FORMAT_XBGR8888; } @@ -485,24 +537,29 @@ static void queue_output_config(struct output_config *oc, } } - if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { - if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 && - bit_depth_from_format(output->wlr_output->render_format) == oc->render_bit_depth) { - // 10-bit was set successfully before, try to save some tests by reusing the format - wlr_output_state_set_render_format(pending, output->wlr_output->render_format); - } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) { - wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010); - } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_6){ - wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565); - } else { - wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); - } + enum render_bit_depth render_bit_depth = get_config_render_bit_depth(oc); + if (render_bit_depth == RENDER_BIT_DEPTH_10 && + bit_depth_from_format(output->wlr_output->render_format) == render_bit_depth) { + // 10-bit was set successfully before, try to save some tests by reusing the format + wlr_output_state_set_render_format(pending, output->wlr_output->render_format); + } else if (render_bit_depth == RENDER_BIT_DEPTH_10) { + wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010); + } else if (render_bit_depth == RENDER_BIT_DEPTH_6) { + wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565); } else { wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); } + + bool hdr = oc && oc->hdr == 1; + if (hdr && oc->color_transform != NULL) { + sway_log(SWAY_ERROR, "Cannot HDR on output %s: output has an ICC profile set", wlr_output->name); + hdr = false; + } + set_hdr(wlr_output, pending, hdr); } -static bool finalize_output_config(struct output_config *oc, struct sway_output *output) { +static bool finalize_output_config(struct output_config *oc, struct sway_output *output, + const struct wlr_output_state *applied) { if (output == root->fallback_output) { return false; } @@ -561,6 +618,7 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0; output->allow_tearing = oc && oc->allow_tearing > 0; + output->hdr = applied->image_description != NULL; return true; } @@ -785,10 +843,7 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx) const struct wlr_drm_format_set *primary_formats = wlr_output_get_primary_formats(wlr_output, server.allocator->buffer_caps); - enum render_bit_depth needed_bits = RENDER_BIT_DEPTH_8; - if (cfg->config && cfg->config->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { - needed_bits = cfg->config->render_bit_depth; - } + enum render_bit_depth needed_bits = get_config_render_bit_depth(cfg->config); for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) { enum render_bit_depth format_bits = bit_depth_from_format(fmts[idx]); if (needed_bits < format_bits) { @@ -943,9 +998,10 @@ static bool apply_resolved_output_configs(struct matched_output_config *configs, for (size_t idx = 0; idx < configs_len; idx++) { struct matched_output_config *cfg = &configs[idx]; + struct wlr_backend_output_state *backend_state = &states[idx]; sway_log(SWAY_DEBUG, "Finalizing config for %s", cfg->output->wlr_output->name); - finalize_output_config(cfg->config, cfg->output); + finalize_output_config(cfg->config, cfg->output, &backend_state->base); } // Output layout being applied in finalize_output_config can shift outputs diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 6a0d462f6..30ed24304 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -406,8 +406,8 @@ 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)); } json_object *ipc_json_describe_disabled_output(struct sway_output *output) { diff --git a/sway/meson.build b/sway/meson.build index 8042c89be..cb03a4d28 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -195,6 +195,7 @@ sway_sources = files( 'commands/output/disable.c', 'commands/output/dpms.c', 'commands/output/enable.c', + 'commands/output/hdr.c', 'commands/output/max_render_time.c', 'commands/output/mode.c', 'commands/output/position.c', diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 833db0ef8..87f0828b7 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -244,6 +244,9 @@ following properties: |- rect : object : The bounds for the output consisting of _x_, _y_, _width_, and _height_ +|- hdr +: boolean +: Whether HDR is enabled *Example Reply:* diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index dfe0d678b..cc48589c3 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -210,6 +210,17 @@ must be separated by one space. For example: This setting only has effect when a window is fullscreen on the output. +*output* hdr on|off|toggle + Enables or disables HDR (High Dynamic Range). HDR enables a larger color + gamut and brightness range. HDR uses the BT2020 primaries and the PQ + transfer function. + + When HDR is enabled, _render_bit_depth_ is implicitly set to 10 unless + explicitly configured. Using a lower render bit depth may result in color + banding artifacts. + + HDR needs to be supported by the output and renderer to be enabled. + # SEE ALSO *sway*(5) *sway-input*(5) diff --git a/swaymsg/main.c b/swaymsg/main.c index 9152b7942..1c6e807cb 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -189,7 +189,8 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "current_workspace", &ws); json_object_object_get_ex(o, "non_desktop", &non_desktop); json_object *make, *model, *serial, *scale, *scale_filter, *subpixel, - *transform, *max_render_time, *adaptive_sync_status, *allow_tearing; + *transform, *max_render_time, *adaptive_sync_status, *allow_tearing, + *hdr; json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "serial", &serial); @@ -200,6 +201,7 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(o, "max_render_time", &max_render_time); json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status); json_object_object_get_ex(o, "allow_tearing", &allow_tearing); + json_object_object_get_ex(o, "hdr", &hdr); json_object *x, *y; json_object_object_get_ex(rect, "x", &x); json_object_object_get_ex(rect, "y", &y); @@ -261,6 +263,7 @@ static void pretty_print_output(json_object *o) { printf(" Allow tearing: %s\n", json_object_get_boolean(allow_tearing) ? "yes" : "no"); + printf(" HDR: %s\n", json_object_get_boolean(hdr) ? "on" : "off"); } else { printf( "Output %s '%s %s %s' (disabled)\n", From 6fed1f9d8933588484e2303e53ac4270a417d78a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 26 Jan 2025 14:36:54 +0100 Subject: [PATCH 3/4] Add support for color-management-v1 References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4962 --- meson.build | 2 +- protocols/meson.build | 1 + sway/server.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index eab1348ae..de5a620c4 100644 --- a/meson.build +++ b/meson.build @@ -65,7 +65,7 @@ pcre2 = dependency('libpcre2-8') wayland_server = dependency('wayland-server', version: '>=1.21.0') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') -wayland_protos = dependency('wayland-protocols', version: '>=1.24', default_options: ['tests=false']) +wayland_protos = dependency('wayland-protocols', version: '>=1.41', default_options: ['tests=false']) xkbcommon = dependency('xkbcommon', version: '>=1.5.0') cairo = dependency('cairo') pango = dependency('pango') diff --git a/protocols/meson.build b/protocols/meson.build index 4d24e7071..3414119b8 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -9,6 +9,7 @@ wayland_scanner = find_program( protocols = [ wl_protocol_dir / 'stable/tablet/tablet-v2.xml', wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', + wl_protocol_dir / 'staging/color-management/color-management-v1.xml', wl_protocol_dir / 'staging/content-type/content-type-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', wl_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', diff --git a/sway/server.c b/sway/server.c index 6ca5906df..fb6204326 100644 --- a/sway/server.c +++ b/sway/server.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -443,6 +444,33 @@ bool server_init(struct sway_server *server) { server->request_set_cursor_shape.notify = handle_request_set_cursor_shape; wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape); + if (server->renderer->features.input_color_transform) { + const enum wp_color_manager_v1_render_intent render_intents[] = { + WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL, + }; + const enum wp_color_manager_v1_transfer_function transfer_functions[] = { + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB, + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ, + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR, + }; + const enum wp_color_manager_v1_primaries primaries[] = { + WP_COLOR_MANAGER_V1_PRIMARIES_SRGB, + WP_COLOR_MANAGER_V1_PRIMARIES_BT2020, + }; + wlr_color_manager_v1_create(server->wl_display, 1, &(struct wlr_color_manager_v1_options){ + .features = { + .parametric = true, + .set_mastering_display_primaries = true, + }, + .render_intents = render_intents, + .render_intents_len = sizeof(render_intents) / sizeof(render_intents[0]), + .transfer_functions = transfer_functions, + .transfer_functions_len = sizeof(transfer_functions) / sizeof(transfer_functions[0]), + .primaries = primaries, + .primaries_len = sizeof(primaries) / sizeof(primaries[0]), + }); + } + wl_list_init(&server->pending_launcher_ctxs); // Avoid using "wayland-0" as display socket From 94c819cc1f9328223509883e4b62939bdf85b760 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Jul 2025 18:52:29 +0200 Subject: [PATCH 4/4] Add features.hdr to output IPC response --- include/sway/output.h | 2 ++ sway/config/output.c | 38 +++++++++++++++++++++----------------- sway/ipc-json.c | 2 ++ swaymsg/main.c | 10 ++++++++-- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 06f8bac23..787527ee7 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -131,6 +131,8 @@ struct sway_container *output_find_container(struct sway_output *output, void output_get_box(struct sway_output *output, struct wlr_box *box); +bool output_supports_hdr(struct wlr_output *output, const char **unsupported_reason_ptr); + enum sway_container_layout output_get_default_layout( struct sway_output *output); diff --git a/sway/config/output.c b/sway/config/output.c index ab2cd2006..2e3c05db3 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -348,22 +348,26 @@ static void set_modeline(struct wlr_output *output, #endif } +bool output_supports_hdr(struct wlr_output *output, const char **unsupported_reason_ptr) { + const char *unsupported_reason = NULL; + if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020)) { + unsupported_reason = "BT2020 primaries not supported by output"; + } else if (!(output->supported_transfer_functions & WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) { + unsupported_reason = "PQ transfer function not supported by output"; + } else if (!server.renderer->features.output_color_transform) { + unsupported_reason = "renderer doesn't support output color transforms"; + } + if (unsupported_reason_ptr != NULL) { + *unsupported_reason_ptr = unsupported_reason; + } + return unsupported_reason == NULL; +} + static void set_hdr(struct wlr_output *output, struct wlr_output_state *pending, bool enabled) { - enum wlr_color_named_primaries primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020; - enum wlr_color_transfer_function tf = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ; - if (enabled && !(output->supported_primaries & primaries)) { - sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: BT2020 primaries not supported by output", - output->name); - enabled = false; - } - if (enabled && !(output->supported_transfer_functions & WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) { - sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: PQ transfer function not supported by output", - output->name); - enabled = false; - } - if (enabled && !server.renderer->features.output_color_transform) { - sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: renderer doesn't support output color transforms", - output->name); + const char *unsupported_reason = NULL; + if (!output_supports_hdr(output, &unsupported_reason)) { + sway_log(SWAY_ERROR, "Cannot enable HDR on output %s: %s", + output->name, unsupported_reason); enabled = false; } @@ -377,8 +381,8 @@ static void set_hdr(struct wlr_output *output, struct wlr_output_state *pending, sway_log(SWAY_DEBUG, "Enabling HDR on output %s", output->name); const struct wlr_output_image_description image_desc = { - .primaries = primaries, - .transfer_function = tf, + .primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020, + .transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ, }; wlr_output_state_set_image_description(pending, &image_desc); } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 30ed24304..3933f3ef7 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -323,6 +323,8 @@ static void ipc_json_describe_wlr_output(struct wlr_output *wlr_output, json_obj json_object_object_add(features_object, "adaptive_sync", json_object_new_boolean(wlr_output->adaptive_sync_supported || wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED)); + json_object_object_add(features_object, "hdr", + json_object_new_boolean(output_supports_hdr(wlr_output, NULL))); json_object_object_add(object, "features", features_object); } diff --git a/swaymsg/main.c b/swaymsg/main.c index 1c6e807cb..d58f29e2c 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -212,9 +212,10 @@ static void pretty_print_output(json_object *o) { json_object_object_get_ex(current_mode, "width", &width); json_object_object_get_ex(current_mode, "height", &height); json_object_object_get_ex(current_mode, "refresh", &refresh); - json_object *features, *features_adaptive_sync; + json_object *features, *features_adaptive_sync, *features_hdr; json_object_object_get_ex(o, "features", &features); json_object_object_get_ex(features, "adaptive_sync", &features_adaptive_sync); + json_object_object_get_ex(features, "hdr", &features_hdr); if (json_object_get_boolean(non_desktop)) { printf( @@ -263,7 +264,12 @@ static void pretty_print_output(json_object *o) { printf(" Allow tearing: %s\n", json_object_get_boolean(allow_tearing) ? "yes" : "no"); - printf(" HDR: %s\n", json_object_get_boolean(hdr) ? "on" : "off"); + + const char *hdr_str = "unsupported"; + if (json_object_get_boolean(features_hdr)) { + hdr_str = json_object_get_boolean(hdr) ? "on" : "off"; + } + printf(" HDR: %s\n", hdr_str); } else { printf( "Output %s '%s %s %s' (disabled)\n",