aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Manuel Stoeckl <code@mstoeckl.com>2023-07-17 21:40:28 -0400
committerLibravatar Simon Ser <contact@emersion.fr>2024-06-07 19:01:49 +0200
commit40ca4150b27a5b94938b6c3d744f74bb26d347f7 (patch)
treea162451f9508eed3a0f7935d6b2e3615e20f03d2
parentUpdate for versioned wlroots files (diff)
downloadsway-40ca4150b27a5b94938b6c3d744f74bb26d347f7.tar.gz
sway-40ca4150b27a5b94938b6c3d744f74bb26d347f7.tar.zst
sway-40ca4150b27a5b94938b6c3d744f74bb26d347f7.zip
sway/commands/output: Add command to set color profile
This makes it possible to render output buffers in a different color space, by specifying an ICC profile for the output.
-rw-r--r--.builds/alpine.yml1
-rw-r--r--.builds/archlinux.yml1
-rw-r--r--.builds/freebsd.yml1
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h3
-rw-r--r--include/sway/output.h2
-rw-r--r--sway/commands/output.c1
-rw-r--r--sway/commands/output/color_profile.c101
-rw-r--r--sway/config/output.c18
-rw-r--r--sway/desktop/output.c5
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway-output.5.scd12
-rw-r--r--sway/tree/output.c1
13 files changed, 147 insertions, 1 deletions
diff --git a/.builds/alpine.yml b/.builds/alpine.yml
index 055e5ffa..7a1fa58e 100644
--- a/.builds/alpine.yml
+++ b/.builds/alpine.yml
@@ -4,6 +4,7 @@ packages:
4 - eudev-dev 4 - eudev-dev
5 - gdk-pixbuf-dev 5 - gdk-pixbuf-dev
6 - json-c-dev 6 - json-c-dev
7 - lcms2-dev
7 - libdisplay-info-dev 8 - libdisplay-info-dev
8 - libevdev-dev 9 - libevdev-dev
9 - libinput-dev 10 - libinput-dev
diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml
index 9972c01a..e249571e 100644
--- a/.builds/archlinux.yml
+++ b/.builds/archlinux.yml
@@ -3,6 +3,7 @@ packages:
3 - cairo 3 - cairo
4 - gdk-pixbuf2 4 - gdk-pixbuf2
5 - json-c 5 - json-c
6 - lcms2
6 - libdisplay-info 7 - libdisplay-info
7 - libegl 8 - libegl
8 - libinput 9 - libinput
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 29c6312a..8084574c 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -8,6 +8,7 @@ packages:
8- devel/pkgconf 8- devel/pkgconf
9- graphics/cairo 9- graphics/cairo
10- graphics/gdk-pixbuf2 10- graphics/gdk-pixbuf2
11- graphics/lcms2
11- graphics/wayland 12- graphics/wayland
12- graphics/wayland-protocols 13- graphics/wayland-protocols
13- textproc/scdoc 14- textproc/scdoc
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 27058587..0a9fdc70 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -283,6 +283,7 @@ sway_cmd input_cmd_xkb_variant;
283 283
284sway_cmd output_cmd_adaptive_sync; 284sway_cmd output_cmd_adaptive_sync;
285sway_cmd output_cmd_background; 285sway_cmd output_cmd_background;
286sway_cmd output_cmd_color_profile;
286sway_cmd output_cmd_disable; 287sway_cmd output_cmd_disable;
287sway_cmd output_cmd_dpms; 288sway_cmd output_cmd_dpms;
288sway_cmd output_cmd_enable; 289sway_cmd output_cmd_enable;
diff --git a/include/sway/config.h b/include/sway/config.h
index 5ccc3e77..3e3a104e 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -7,6 +7,7 @@
7#include <wlr/interfaces/wlr_switch.h> 7#include <wlr/interfaces/wlr_switch.h>
8#include <wlr/types/wlr_tablet_tool.h> 8#include <wlr/types/wlr_tablet_tool.h>
9#include <wlr/util/box.h> 9#include <wlr/util/box.h>
10#include <wlr/render/color.h>
10#include <xkbcommon/xkbcommon.h> 11#include <xkbcommon/xkbcommon.h>
11#include <xf86drmMode.h> 12#include <xf86drmMode.h>
12#include "../include/config.h" 13#include "../include/config.h"
@@ -285,6 +286,8 @@ struct output_config {
285 int max_render_time; // In milliseconds 286 int max_render_time; // In milliseconds
286 int adaptive_sync; 287 int adaptive_sync;
287 enum render_bit_depth render_bit_depth; 288 enum render_bit_depth render_bit_depth;
289 bool set_color_transform;
290 struct wlr_color_transform *color_transform;
288 291
289 char *background; 292 char *background;
290 char *background_option; 293 char *background_option;
diff --git a/include/sway/output.h b/include/sway/output.h
index d546d488..2189c6e8 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -66,6 +66,8 @@ struct sway_output {
66 struct wl_signal disable; 66 struct wl_signal disable;
67 } events; 67 } events;
68 68
69 struct wlr_color_transform *color_transform;
70
69 struct timespec last_presentation; 71 struct timespec last_presentation;
70 uint32_t refresh_nsec; 72 uint32_t refresh_nsec;
71 int max_render_time; // In milliseconds 73 int max_render_time; // In milliseconds
diff --git a/sway/commands/output.c b/sway/commands/output.c
index 5e5d31b3..b822e770 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -10,6 +10,7 @@ static const struct cmd_handler output_handlers[] = {
10 { "adaptive_sync", output_cmd_adaptive_sync }, 10 { "adaptive_sync", output_cmd_adaptive_sync },
11 { "background", output_cmd_background }, 11 { "background", output_cmd_background },
12 { "bg", output_cmd_background }, 12 { "bg", output_cmd_background },
13 { "color_profile", output_cmd_color_profile },
13 { "disable", output_cmd_disable }, 14 { "disable", output_cmd_disable },
14 { "dpms", output_cmd_dpms }, 15 { "dpms", output_cmd_dpms },
15 { "enable", output_cmd_enable }, 16 { "enable", output_cmd_enable },
diff --git a/sway/commands/output/color_profile.c b/sway/commands/output/color_profile.c
new file mode 100644
index 00000000..792bd55f
--- /dev/null
+++ b/sway/commands/output/color_profile.c
@@ -0,0 +1,101 @@
1#include <fcntl.h>
2#include <strings.h>
3#include <sys/stat.h>
4#include <unistd.h>
5#include <wlr/render/color.h>
6#include "sway/commands.h"
7#include "sway/config.h"
8
9static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
10 /* Why not use fopen/fread directly? glibc will succesfully open directories,
11 * not just files, and supports seeking on them. Instead, we directly
12 * work with file descriptors and use the more consistent open/fstat/read. */
13 int fd = open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
14 if (fd == -1) {
15 return false;
16 }
17 char *b = NULL;
18 struct stat info;
19 if (fstat(fd, &info) == -1) {
20 goto fail;
21 }
22 // only regular files, to avoid issues with e.g. opening pipes
23 if (!S_ISREG(info.st_mode)) {
24 goto fail;
25 }
26 off_t s = info.st_size;
27 if (s <= 0) {
28 goto fail;
29 }
30 b = calloc(1, s);
31 if (!b) {
32 goto fail;
33 }
34 size_t nread = 0;
35 while (nread < (size_t)s) {
36 size_t to_read = (size_t)s - nread;
37 ssize_t r = read(fd, b + nread, to_read);
38 if ((r == -1 && errno != EINTR) || r == 0) {
39 goto fail;
40 }
41 nread += (size_t)r;
42 }
43 close(fd);
44 *buf = b;
45 *size = (size_t)s;
46 return true; // success
47fail:
48 free(b);
49 close(fd);
50 return false;
51}
52
53struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
54 if (!config->handler_context.output_config) {
55 return cmd_results_new(CMD_FAILURE, "Missing output config");
56 }
57 if (!argc) {
58 return cmd_results_new(CMD_INVALID, "Missing color_profile first argument.");
59 }
60
61 if (strcmp(*argv, "srgb") == 0) {
62 wlr_color_transform_unref(config->handler_context.output_config->color_transform);
63 config->handler_context.output_config->color_transform = NULL;
64 config->handler_context.output_config->set_color_transform = true;
65
66 config->handler_context.leftovers.argc = argc - 1;
67 config->handler_context.leftovers.argv = argv + 1;
68 } else if (strcmp(*argv, "icc") == 0) {
69 if (argc < 2) {
70 return cmd_results_new(CMD_INVALID,
71 "Invalid color profile specification: icc type requires a file");
72 }
73 void *data = NULL;
74 size_t size = 0;
75 if (!read_file_into_buf(argv[1], &data, &size)) {
76 return cmd_results_new(CMD_FAILURE,
77 "Failed to load color profile: could not read ICC file");
78 }
79
80 struct wlr_color_transform *tmp =
81 wlr_color_transform_init_linear_to_icc(data, size);
82 if (!tmp) {
83 free(data);
84 return cmd_results_new(CMD_FAILURE,
85 "Failed to load color profile: failed to initialize transform from ICC");
86 }
87 free(data);
88
89 wlr_color_transform_unref(config->handler_context.output_config->color_transform);
90 config->handler_context.output_config->color_transform = tmp;
91 config->handler_context.output_config->set_color_transform = true;
92
93 config->handler_context.leftovers.argc = argc - 2;
94 config->handler_context.leftovers.argv = argv + 2;
95 } else {
96 return cmd_results_new(CMD_INVALID,
97 "Invalid color profile specification: first argument should be icc|srgb");
98 }
99
100 return NULL;
101}
diff --git a/sway/config/output.c b/sway/config/output.c
index 9a447388..bcd21b9b 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -76,6 +76,8 @@ struct output_config *new_output_config(const char *name) {
76 oc->max_render_time = -1; 76 oc->max_render_time = -1;
77 oc->adaptive_sync = -1; 77 oc->adaptive_sync = -1;
78 oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; 78 oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
79 oc->set_color_transform = false;
80 oc->color_transform = NULL;
79 oc->power = -1; 81 oc->power = -1;
80 return oc; 82 return oc;
81} 83}
@@ -191,6 +193,14 @@ static void merge_output_config(struct output_config *dst, struct output_config
191 if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { 193 if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
192 dst->render_bit_depth = src->render_bit_depth; 194 dst->render_bit_depth = src->render_bit_depth;
193 } 195 }
196 if (src->set_color_transform) {
197 if (src->color_transform) {
198 wlr_color_transform_ref(src->color_transform);
199 }
200 wlr_color_transform_unref(dst->color_transform);
201 dst->set_color_transform = true;
202 dst->color_transform = src->color_transform;
203 }
194 if (src->background) { 204 if (src->background) {
195 free(dst->background); 205 free(dst->background);
196 dst->background = strdup(src->background); 206 dst->background = strdup(src->background);
@@ -557,6 +567,13 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
557 output->max_render_time = oc->max_render_time; 567 output->max_render_time = oc->max_render_time;
558 } 568 }
559 569
570 if (oc && oc->set_color_transform) {
571 if (oc->color_transform) {
572 wlr_color_transform_ref(oc->color_transform);
573 }
574 wlr_color_transform_unref(output->color_transform);
575 output->color_transform = oc->color_transform;
576 }
560 return true; 577 return true;
561} 578}
562 579
@@ -997,6 +1014,7 @@ void free_output_config(struct output_config *oc) {
997 free(oc->name); 1014 free(oc->name);
998 free(oc->background); 1015 free(oc->background);
999 free(oc->background_option); 1016 free(oc->background_option);
1017 wlr_color_transform_unref(oc->color_transform);
1000 free(oc); 1018 free(oc);
1001} 1019}
1002 1020
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 2722e556..cfa53021 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -269,7 +269,10 @@ static int output_repaint_timer_handler(void *data) {
269 return 0; 269 return 0;
270 } 270 }
271 271
272 wlr_scene_output_commit(output->scene_output, NULL); 272 struct wlr_scene_output_state_options opts = {
273 .color_transform = output->color_transform,
274 };
275 wlr_scene_output_commit(output->scene_output, &opts);
273 return 0; 276 return 0;
274} 277}
275 278
diff --git a/sway/meson.build b/sway/meson.build
index 47b51d0c..a189fe9a 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -202,6 +202,7 @@ sway_sources = files(
202 'commands/output/toggle.c', 202 'commands/output/toggle.c',
203 'commands/output/transform.c', 203 'commands/output/transform.c',
204 'commands/output/unplug.c', 204 'commands/output/unplug.c',
205 'commands/output/color_profile.c',
205 206
206 'tree/arrange.c', 207 'tree/arrange.c',
207 'tree/container.c', 208 'tree/container.c',
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 7d088d5d..6d7c0860 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -178,6 +178,18 @@ must be separated by one space. For example:
178 updated to work with different bit depths. This command is experimental, 178 updated to work with different bit depths. This command is experimental,
179 and may be removed or changed in the future. 179 and may be removed or changed in the future.
180 180
181*output* <name> color_profile srgb|[icc <file>]
182 Sets the color profile for an output. The default is _srgb_. <file> should be a
183 path to a display ICC profile.
184
185 Not all renderers support this feature; currently it only works with the
186 the Vulkan renderer. Even where supported, the application of the color
187 profile may be inaccurate.
188
189 This command is experimental, and may be removed or changed in the future. It
190 may have no effect or produce unexpected output when used together with future
191 HDR support features.
192
181# SEE ALSO 193# SEE ALSO
182 194
183*sway*(5) *sway-input*(5) 195*sway*(5) *sway-input*(5)
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 2d11195e..6c8dd6dc 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -279,6 +279,7 @@ void output_destroy(struct sway_output *output) {
279 list_free(output->workspaces); 279 list_free(output->workspaces);
280 list_free(output->current.workspaces); 280 list_free(output->current.workspaces);
281 wl_event_source_remove(output->repaint_timer); 281 wl_event_source_remove(output->repaint_timer);
282 wlr_color_transform_unref(output->color_transform);
282 free(output); 283 free(output);
283} 284}
284 285