aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ronan Pigott <rpigott@berkeley.edu>2019-11-13 11:23:36 -0700
committerLibravatar Simon Ser <contact@emersion.fr>2019-11-29 18:13:37 +0100
commit6968fb3123e69f563cd01d472967a9e6ddca2ec1 (patch)
tree0e313d5e19da37762ab572e38c36ff33798f25fb
parentoutput: Ensure that frame_done is delayed on max_render_time (diff)
downloadsway-6968fb3123e69f563cd01d472967a9e6ddca2ec1.tar.gz
sway-6968fb3123e69f563cd01d472967a9e6ddca2ec1.tar.zst
sway-6968fb3123e69f563cd01d472967a9e6ddca2ec1.zip
add scale_filter output config option
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h10
-rw-r--r--include/sway/output.h1
-rw-r--r--meson.build1
-rw-r--r--sway/commands/output.c1
-rw-r--r--sway/commands/output/scale_filter.c34
-rw-r--r--sway/config/output.c38
-rw-r--r--sway/desktop/render.c26
-rw-r--r--sway/ipc-json.c3
-rw-r--r--sway/meson.build2
-rw-r--r--sway/sway-output.5.scd8
-rw-r--r--sway/tree/output.c1
-rw-r--r--swaymsg/main.c6
13 files changed, 131 insertions, 1 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 67665d87..5f249980 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -276,6 +276,7 @@ sway_cmd output_cmd_max_render_time;
276sway_cmd output_cmd_mode; 276sway_cmd output_cmd_mode;
277sway_cmd output_cmd_position; 277sway_cmd output_cmd_position;
278sway_cmd output_cmd_scale; 278sway_cmd output_cmd_scale;
279sway_cmd output_cmd_scale_filter;
279sway_cmd output_cmd_subpixel; 280sway_cmd output_cmd_subpixel;
280sway_cmd output_cmd_toggle; 281sway_cmd output_cmd_toggle;
281sway_cmd output_cmd_transform; 282sway_cmd output_cmd_transform;
diff --git a/include/sway/config.h b/include/sway/config.h
index ed542790..9a00ccb5 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -204,6 +204,13 @@ enum config_dpms {
204 DPMS_OFF 204 DPMS_OFF
205}; 205};
206 206
207enum scale_filter_mode {
208 SCALE_FILTER_DEFAULT, // the default is currently smart
209 SCALE_FILTER_LINEAR,
210 SCALE_FILTER_NEAREST,
211 SCALE_FILTER_SMART
212};
213
207/** 214/**
208 * Size and position configuration for a particular output. 215 * Size and position configuration for a particular output.
209 * 216 *
@@ -217,6 +224,7 @@ struct output_config {
217 int custom_mode; 224 int custom_mode;
218 int x, y; 225 int x, y;
219 float scale; 226 float scale;
227 enum scale_filter_mode scale_filter;
220 int32_t transform; 228 int32_t transform;
221 enum wl_output_subpixel subpixel; 229 enum wl_output_subpixel subpixel;
222 int max_render_time; // In milliseconds 230 int max_render_time; // In milliseconds
@@ -655,6 +663,8 @@ int output_name_cmp(const void *item, const void *data);
655void output_get_identifier(char *identifier, size_t len, 663void output_get_identifier(char *identifier, size_t len,
656 struct sway_output *output); 664 struct sway_output *output);
657 665
666const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter);
667
658struct output_config *new_output_config(const char *name); 668struct output_config *new_output_config(const char *name);
659 669
660void merge_output_config(struct output_config *dst, struct output_config *src); 670void merge_output_config(struct output_config *dst, struct output_config *src);
diff --git a/include/sway/output.h b/include/sway/output.h
index ddc08022..bc03f4c5 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -32,6 +32,7 @@ struct sway_output {
32 int lx, ly; // layout coords 32 int lx, ly; // layout coords
33 int width, height; // transformed buffer size 33 int width, height; // transformed buffer size
34 enum wl_output_subpixel detected_subpixel; 34 enum wl_output_subpixel detected_subpixel;
35 enum scale_filter_mode scale_filter;
35 // last applied mode when the output is DPMS'ed 36 // last applied mode when the output is DPMS'ed
36 struct wlr_output_mode *current_mode; 37 struct wlr_output_mode *current_mode;
37 38
diff --git a/meson.build b/meson.build
index 160c921f..70afcd50 100644
--- a/meson.build
+++ b/meson.build
@@ -48,6 +48,7 @@ pango = dependency('pango')
48pangocairo = dependency('pangocairo') 48pangocairo = dependency('pangocairo')
49gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) 49gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
50pixman = dependency('pixman-1') 50pixman = dependency('pixman-1')
51glesv2 = dependency('glesv2')
51libevdev = dependency('libevdev') 52libevdev = dependency('libevdev')
52libinput = dependency('libinput', version: '>=1.6.0') 53libinput = dependency('libinput', version: '>=1.6.0')
53systemd = dependency('libsystemd', version: '>=239', required: false) 54systemd = dependency('libsystemd', version: '>=239', required: false)
diff --git a/sway/commands/output.c b/sway/commands/output.c
index db2acb50..2790bd63 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -19,6 +19,7 @@ static struct cmd_handler output_handlers[] = {
19 { "res", output_cmd_mode }, 19 { "res", output_cmd_mode },
20 { "resolution", output_cmd_mode }, 20 { "resolution", output_cmd_mode },
21 { "scale", output_cmd_scale }, 21 { "scale", output_cmd_scale },
22 { "scale_filter", output_cmd_scale_filter },
22 { "subpixel", output_cmd_subpixel }, 23 { "subpixel", output_cmd_subpixel },
23 { "toggle", output_cmd_toggle }, 24 { "toggle", output_cmd_toggle },
24 { "transform", output_cmd_transform }, 25 { "transform", output_cmd_transform },
diff --git a/sway/commands/output/scale_filter.c b/sway/commands/output/scale_filter.c
new file mode 100644
index 00000000..fa1e8e0d
--- /dev/null
+++ b/sway/commands/output/scale_filter.c
@@ -0,0 +1,34 @@
1#include <string.h>
2#include "log.h"
3#include "sway/commands.h"
4#include "sway/config.h"
5#include "sway/output.h"
6
7struct cmd_results *output_cmd_scale_filter(int argc, char **argv) {
8 if (!config->handler_context.output_config) {
9 return cmd_results_new(CMD_FAILURE, "Missing output config");
10 }
11
12 if (!argc) {
13 return cmd_results_new(CMD_INVALID, "Missing scale_filter argument.");
14 }
15
16
17 enum scale_filter_mode scale_filter;
18 if (strcmp(*argv, "linear") == 0) {
19 scale_filter = SCALE_FILTER_LINEAR;
20 } else if (strcmp(*argv, "nearest") == 0) {
21 scale_filter = SCALE_FILTER_NEAREST;
22 } else if (strcmp(*argv, "smart") == 0) {
23 scale_filter = SCALE_FILTER_SMART;
24 } else {
25 return cmd_results_new(CMD_INVALID, "Invalid output scale_filter.");
26 }
27
28 struct output_config *oc = config->handler_context.output_config;
29 config->handler_context.leftovers.argc = argc - 1;
30 config->handler_context.leftovers.argv = argv + 1;
31
32 oc->scale_filter = scale_filter;
33 return NULL;
34}
diff --git a/sway/config/output.c b/sway/config/output.c
index 1d5f81da..21a12b8f 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -29,6 +29,21 @@ void output_get_identifier(char *identifier, size_t len,
29 wlr_output->serial); 29 wlr_output->serial);
30} 30}
31 31
32const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
33 switch (scale_filter) {
34 case SCALE_FILTER_DEFAULT:
35 return "smart";
36 case SCALE_FILTER_LINEAR:
37 return "linear";
38 case SCALE_FILTER_NEAREST:
39 return "nearest";
40 case SCALE_FILTER_SMART:
41 return "smart";
42 }
43 sway_assert(false, "Unknown value for scale_filter.");
44 return NULL;
45}
46
32struct output_config *new_output_config(const char *name) { 47struct output_config *new_output_config(const char *name) {
33 struct output_config *oc = calloc(1, sizeof(struct output_config)); 48 struct output_config *oc = calloc(1, sizeof(struct output_config));
34 if (oc == NULL) { 49 if (oc == NULL) {
@@ -45,6 +60,7 @@ struct output_config *new_output_config(const char *name) {
45 oc->custom_mode = -1; 60 oc->custom_mode = -1;
46 oc->x = oc->y = -1; 61 oc->x = oc->y = -1;
47 oc->scale = -1; 62 oc->scale = -1;
63 oc->scale_filter = SCALE_FILTER_DEFAULT;
48 oc->transform = -1; 64 oc->transform = -1;
49 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; 65 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
50 oc->max_render_time = -1; 66 oc->max_render_time = -1;
@@ -70,6 +86,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
70 if (src->scale != -1) { 86 if (src->scale != -1) {
71 dst->scale = src->scale; 87 dst->scale = src->scale;
72 } 88 }
89 if (src->scale_filter != SCALE_FILTER_DEFAULT) {
90 dst->scale_filter = src->scale_filter;
91 }
73 if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { 92 if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
74 dst->subpixel = src->subpixel; 93 dst->subpixel = src->subpixel;
75 } 94 }
@@ -297,6 +316,24 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
297 if (oc && oc->scale > 0) { 316 if (oc && oc->scale > 0) {
298 sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale); 317 sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
299 wlr_output_set_scale(wlr_output, oc->scale); 318 wlr_output_set_scale(wlr_output, oc->scale);
319
320 enum scale_filter_mode scale_filter_old = output->scale_filter;
321 switch (oc->scale_filter) {
322 case SCALE_FILTER_DEFAULT:
323 case SCALE_FILTER_SMART:
324 output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ?
325 SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR;
326 break;
327 case SCALE_FILTER_LINEAR:
328 case SCALE_FILTER_NEAREST:
329 output->scale_filter = oc->scale_filter;
330 break;
331 }
332 if (scale_filter_old != output->scale_filter) {
333 sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
334 sway_output_scale_filter_to_string(output->scale_filter));
335 output_damage_whole(output);
336 }
300 } 337 }
301 338
302 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { 339 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
@@ -352,6 +389,7 @@ static void default_output_config(struct output_config *oc,
352 } 389 }
353 oc->x = oc->y = -1; 390 oc->x = oc->y = -1;
354 oc->scale = 1; 391 oc->scale = 1;
392 oc->scale_filter = SCALE_FILTER_DEFAULT;
355 struct sway_output *output = wlr_output->data; 393 struct sway_output *output = wlr_output->data;
356 oc->subpixel = output->detected_subpixel; 394 oc->subpixel = output->detected_subpixel;
357 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; 395 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 960fe083..2e66abd4 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -1,9 +1,11 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <GLES2/gl2.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <strings.h> 5#include <strings.h>
5#include <time.h> 6#include <time.h>
6#include <wayland-server-core.h> 7#include <wayland-server-core.h>
8#include <wlr/render/gles2.h>
7#include <wlr/render/wlr_renderer.h> 9#include <wlr/render/wlr_renderer.h>
8#include <wlr/types/wlr_box.h> 10#include <wlr/types/wlr_box.h>
9#include <wlr/types/wlr_buffer.h> 11#include <wlr/types/wlr_buffer.h>
@@ -70,6 +72,28 @@ static void scissor_output(struct wlr_output *wlr_output,
70 wlr_renderer_scissor(renderer, &box); 72 wlr_renderer_scissor(renderer, &box);
71} 73}
72 74
75static void set_scale_filter(struct wlr_output *wlr_output,
76 struct wlr_texture *texture, enum scale_filter_mode scale_filter) {
77 if (!wlr_texture_is_gles2(texture)) {
78 return;
79 }
80
81 struct wlr_gles2_texture_attribs attribs;
82 wlr_gles2_texture_get_attribs(texture, &attribs);
83
84 switch (scale_filter) {
85 case SCALE_FILTER_LINEAR:
86 glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
87 break;
88 case SCALE_FILTER_NEAREST:
89 glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
90 break;
91 case SCALE_FILTER_DEFAULT:
92 case SCALE_FILTER_SMART:
93 assert(false); // unreachable
94 }
95}
96
73static void render_texture(struct wlr_output *wlr_output, 97static void render_texture(struct wlr_output *wlr_output,
74 pixman_region32_t *output_damage, struct wlr_texture *texture, 98 pixman_region32_t *output_damage, struct wlr_texture *texture,
75 const struct wlr_box *box, const float matrix[static 9], float alpha) { 99 const struct wlr_box *box, const float matrix[static 9], float alpha) {
@@ -119,6 +143,7 @@ static void render_surface_iterator(struct sway_output *output, struct sway_view
119 wlr_matrix_project_box(matrix, &box, transform, rotation, 143 wlr_matrix_project_box(matrix, &box, transform, rotation,
120 wlr_output->transform_matrix); 144 wlr_output->transform_matrix);
121 145
146 set_scale_filter(wlr_output, texture, output->scale_filter);
122 render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); 147 render_texture(wlr_output, output_damage, texture, &box, matrix, alpha);
123 148
124 wlr_presentation_surface_sampled_on_output(server.presentation, surface, 149 wlr_presentation_surface_sampled_on_output(server.presentation, surface,
@@ -268,6 +293,7 @@ static void render_saved_view(struct sway_view *view,
268 wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, 293 wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
269 wlr_output->transform_matrix); 294 wlr_output->transform_matrix);
270 295
296 set_scale_filter(wlr_output, view->saved_buffer->texture, output->scale_filter);
271 render_texture(wlr_output, damage, view->saved_buffer->texture, 297 render_texture(wlr_output, damage, view->saved_buffer->texture,
272 &box, matrix, alpha); 298 &box, matrix, alpha);
273 299
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index b880eb65..6cf8504a 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -177,6 +177,9 @@ static void ipc_json_describe_output(struct sway_output *output,
177 json_object_new_string(wlr_output->serial)); 177 json_object_new_string(wlr_output->serial));
178 json_object_object_add(object, "scale", 178 json_object_object_add(object, "scale",
179 json_object_new_double(wlr_output->scale)); 179 json_object_new_double(wlr_output->scale));
180 json_object_object_add(object, "scale_filter",
181 json_object_new_string(
182 sway_output_scale_filter_to_string(output->scale_filter)));
180 json_object_object_add(object, "transform", 183 json_object_object_add(object, "transform",
181 json_object_new_string( 184 json_object_new_string(
182 ipc_json_output_transform_description(wlr_output->transform))); 185 ipc_json_output_transform_description(wlr_output->transform)));
diff --git a/sway/meson.build b/sway/meson.build
index 5458d3dc..3e6e4da6 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -182,6 +182,7 @@ sway_sources = files(
182 'commands/output/mode.c', 182 'commands/output/mode.c',
183 'commands/output/position.c', 183 'commands/output/position.c',
184 'commands/output/scale.c', 184 'commands/output/scale.c',
185 'commands/output/scale_filter.c',
185 'commands/output/subpixel.c', 186 'commands/output/subpixel.c',
186 'commands/output/toggle.c', 187 'commands/output/toggle.c',
187 'commands/output/transform.c', 188 'commands/output/transform.c',
@@ -203,6 +204,7 @@ sway_deps = [
203 math, 204 math,
204 pango, 205 pango,
205 pcre, 206 pcre,
207 glesv2,
206 pixman, 208 pixman,
207 server_protos, 209 server_protos,
208 wayland_server, 210 wayland_server,
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 3824480f..2dfb2ac1 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -70,6 +70,14 @@ must be separated by one space. For example:
70 applications to taste. HiDPI isn't supported with Xwayland clients (windows 70 applications to taste. HiDPI isn't supported with Xwayland clients (windows
71 will blur). 71 will blur).
72 72
73*output* <name> scale_filter linear|nearest|smart
74 Indicates how to scale application buffers that are rendered at a scale
75 lower than the output's configured scale, such as lo-dpi applications on
76 hi-dpi screens. Linear is smoother and blurrier, nearest (also known as
77 nearest neighbor) is sharper and blockier. Setting "smart" will apply
78 nearest scaling when the output has an integer scale factor, otherwise
79 linear. The default is "smart".
80
73*output* <name> subpixel rgb|bgr|vrgb|vbgr|none 81*output* <name> subpixel rgb|bgr|vrgb|vbgr|none
74 Manually sets the subpixel hinting for the specified output. This value is 82 Manually sets the subpixel hinting for the specified output. This value is
75 usually auto-detected, but some displays may misreport their subpixel 83 usually auto-detected, but some displays may misreport their subpixel
diff --git a/sway/tree/output.c b/sway/tree/output.c
index c4ec6eec..d2ede1f2 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -93,6 +93,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
93 output->wlr_output = wlr_output; 93 output->wlr_output = wlr_output;
94 wlr_output->data = output; 94 wlr_output->data = output;
95 output->detected_subpixel = wlr_output->subpixel; 95 output->detected_subpixel = wlr_output->subpixel;
96 output->scale_filter = SCALE_FILTER_NEAREST;
96 97
97 wl_signal_init(&output->events.destroy); 98 wl_signal_init(&output->events.destroy);
98 99
diff --git a/swaymsg/main.c b/swaymsg/main.c
index 596cf4ef..b9a8189c 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -189,11 +189,13 @@ static void pretty_print_output(json_object *o) {
189 json_object_object_get_ex(o, "focused", &focused); 189 json_object_object_get_ex(o, "focused", &focused);
190 json_object_object_get_ex(o, "active", &active); 190 json_object_object_get_ex(o, "active", &active);
191 json_object_object_get_ex(o, "current_workspace", &ws); 191 json_object_object_get_ex(o, "current_workspace", &ws);
192 json_object *make, *model, *serial, *scale, *subpixel, *transform, *max_render_time; 192 json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
193 *transform, *max_render_time;
193 json_object_object_get_ex(o, "make", &make); 194 json_object_object_get_ex(o, "make", &make);
194 json_object_object_get_ex(o, "model", &model); 195 json_object_object_get_ex(o, "model", &model);
195 json_object_object_get_ex(o, "serial", &serial); 196 json_object_object_get_ex(o, "serial", &serial);
196 json_object_object_get_ex(o, "scale", &scale); 197 json_object_object_get_ex(o, "scale", &scale);
198 json_object_object_get_ex(o, "scale_filter", &scale_filter);
197 json_object_object_get_ex(o, "subpixel_hinting", &subpixel); 199 json_object_object_get_ex(o, "subpixel_hinting", &subpixel);
198 json_object_object_get_ex(o, "transform", &transform); 200 json_object_object_get_ex(o, "transform", &transform);
199 json_object_object_get_ex(o, "max_render_time", &max_render_time); 201 json_object_object_get_ex(o, "max_render_time", &max_render_time);
@@ -214,6 +216,7 @@ static void pretty_print_output(json_object *o) {
214 " Current mode: %dx%d @ %f Hz\n" 216 " Current mode: %dx%d @ %f Hz\n"
215 " Position: %d,%d\n" 217 " Position: %d,%d\n"
216 " Scale factor: %f\n" 218 " Scale factor: %f\n"
219 " Scale filter: %s\n"
217 " Subpixel hinting: %s\n" 220 " Subpixel hinting: %s\n"
218 " Transform: %s\n" 221 " Transform: %s\n"
219 " Workspace: %s\n" 222 " Workspace: %s\n"
@@ -228,6 +231,7 @@ static void pretty_print_output(json_object *o) {
228 (float)json_object_get_int(refresh) / 1000, 231 (float)json_object_get_int(refresh) / 1000,
229 json_object_get_int(x), json_object_get_int(y), 232 json_object_get_int(x), json_object_get_int(y),
230 json_object_get_double(scale), 233 json_object_get_double(scale),
234 json_object_get_string(scale_filter),
231 json_object_get_string(subpixel), 235 json_object_get_string(subpixel),
232 json_object_get_string(transform), 236 json_object_get_string(transform),
233 json_object_get_string(ws) 237 json_object_get_string(ws)