aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Ivan Molodetskikh <yalterz@gmail.com>2019-09-25 17:35:41 +0300
committerLibravatar Simon Ser <contact@emersion.fr>2019-11-17 20:18:42 +0100
commitbd9a53f1a3e7dba247aab0a4e4268724acc12c38 (patch)
tree1547b79a82b1c4e22512d0262cbb133a14ef10a3
parentAdd sway_surface (diff)
downloadsway-bd9a53f1a3e7dba247aab0a4e4268724acc12c38.tar.gz
sway-bd9a53f1a3e7dba247aab0a4e4268724acc12c38.tar.zst
sway-bd9a53f1a3e7dba247aab0a4e4268724acc12c38.zip
view: add max_render_time
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/output.h2
-rw-r--r--include/sway/surface.h7
-rw-r--r--include/sway/tree/view.h2
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/max_render_time.c32
-rw-r--r--sway/desktop/output.c55
-rw-r--r--sway/desktop/render.c6
-rw-r--r--sway/desktop/surface.c17
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway-output.5.scd3
-rw-r--r--sway/sway.5.scd16
12 files changed, 125 insertions, 18 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 5d468a42..45b5b0f4 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -145,6 +145,7 @@ sway_cmd cmd_kill;
145sway_cmd cmd_layout; 145sway_cmd cmd_layout;
146sway_cmd cmd_log_colors; 146sway_cmd cmd_log_colors;
147sway_cmd cmd_mark; 147sway_cmd cmd_mark;
148sway_cmd cmd_max_render_time;
148sway_cmd cmd_mode; 149sway_cmd cmd_mode;
149sway_cmd cmd_mouse_warping; 150sway_cmd cmd_mouse_warping;
150sway_cmd cmd_move; 151sway_cmd cmd_move;
diff --git a/include/sway/output.h b/include/sway/output.h
index 741f5b5e..ddc08022 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -72,7 +72,7 @@ struct sway_output *output_get_in_direction(struct sway_output *reference,
72void output_add_workspace(struct sway_output *output, 72void output_add_workspace(struct sway_output *output,
73 struct sway_workspace *workspace); 73 struct sway_workspace *workspace);
74 74
75typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, 75typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, struct sway_view *view,
76 struct wlr_surface *surface, struct wlr_box *box, float rotation, 76 struct wlr_surface *surface, struct wlr_box *box, float rotation,
77 void *user_data); 77 void *user_data);
78 78
diff --git a/include/sway/surface.h b/include/sway/surface.h
index 06874af2..4da96c02 100644
--- a/include/sway/surface.h
+++ b/include/sway/surface.h
@@ -6,6 +6,13 @@ struct sway_surface {
6 struct wlr_surface *wlr_surface; 6 struct wlr_surface *wlr_surface;
7 7
8 struct wl_listener destroy; 8 struct wl_listener destroy;
9
10 /**
11 * This timer can be used for issuing delayed frame done callbacks (for
12 * example, to improve presentation latency). Its handler is set to a
13 * function that issues a frame done callback to this surface.
14 */
15 struct wl_event_source *frame_done_timer;
9}; 16};
10 17
11#endif 18#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 44cd4a7b..29c87967 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -108,6 +108,8 @@ struct sway_view {
108 } events; 108 } events;
109 109
110 struct wl_listener surface_new_subsurface; 110 struct wl_listener surface_new_subsurface;
111
112 int max_render_time; // In milliseconds
111}; 113};
112 114
113struct sway_xdg_shell_view { 115struct sway_xdg_shell_view {
diff --git a/sway/commands.c b/sway/commands.c
index e2c43e9f..e7f1eafe 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -119,6 +119,7 @@ static struct cmd_handler command_handlers[] = {
119 { "kill", cmd_kill }, 119 { "kill", cmd_kill },
120 { "layout", cmd_layout }, 120 { "layout", cmd_layout },
121 { "mark", cmd_mark }, 121 { "mark", cmd_mark },
122 { "max_render_time", cmd_max_render_time },
122 { "move", cmd_move }, 123 { "move", cmd_move },
123 { "nop", cmd_nop }, 124 { "nop", cmd_nop },
124 { "opacity", cmd_opacity }, 125 { "opacity", cmd_opacity },
diff --git a/sway/commands/max_render_time.c b/sway/commands/max_render_time.c
new file mode 100644
index 00000000..ec3282f1
--- /dev/null
+++ b/sway/commands/max_render_time.c
@@ -0,0 +1,32 @@
1#include <strings.h>
2#include "sway/commands.h"
3#include "sway/config.h"
4#include "sway/tree/view.h"
5
6struct cmd_results *cmd_max_render_time(int argc, char **argv) {
7 if (!argc) {
8 return cmd_results_new(CMD_INVALID, "Missing max render time argument.");
9 }
10
11 int max_render_time;
12 if (!strcmp(*argv, "off")) {
13 max_render_time = 0;
14 } else {
15 char *end;
16 max_render_time = strtol(*argv, &end, 10);
17 if (*end || max_render_time <= 0) {
18 return cmd_results_new(CMD_INVALID, "Invalid max render time.");
19 }
20 }
21
22 struct sway_container *container = config->handler_context.container;
23 if (!container || !container->view) {
24 return cmd_results_new(CMD_INVALID,
25 "Only views can have a max_render_time");
26 }
27
28 struct sway_view *view = container->view;
29 view->max_render_time = max_render_time;
30
31 return cmd_results_new(CMD_SUCCESS, NULL);
32}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 0f715c19..6498198b 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -23,6 +23,7 @@
23#include "sway/layers.h" 23#include "sway/layers.h"
24#include "sway/output.h" 24#include "sway/output.h"
25#include "sway/server.h" 25#include "sway/server.h"
26#include "sway/surface.h"
26#include "sway/tree/arrange.h" 27#include "sway/tree/arrange.h"
27#include "sway/tree/container.h" 28#include "sway/tree/container.h"
28#include "sway/tree/root.h" 29#include "sway/tree/root.h"
@@ -80,6 +81,7 @@ struct surface_iterator_data {
80 void *user_data; 81 void *user_data;
81 82
82 struct sway_output *output; 83 struct sway_output *output;
84 struct sway_view *view;
83 double ox, oy; 85 double ox, oy;
84 int width, height; 86 int width, height;
85 float rotation; 87 float rotation;
@@ -134,7 +136,7 @@ static void output_for_each_surface_iterator(struct wlr_surface *surface,
134 return; 136 return;
135 } 137 }
136 138
137 data->user_iterator(data->output, surface, &box, data->rotation, 139 data->user_iterator(data->output, data->view, surface, &box, data->rotation,
138 data->user_data); 140 data->user_data);
139} 141}
140 142
@@ -145,6 +147,7 @@ void output_surface_for_each_surface(struct sway_output *output,
145 .user_iterator = iterator, 147 .user_iterator = iterator,
146 .user_data = user_data, 148 .user_data = user_data,
147 .output = output, 149 .output = output,
150 .view = NULL,
148 .ox = ox, 151 .ox = ox,
149 .oy = oy, 152 .oy = oy,
150 .width = surface->current.width, 153 .width = surface->current.width,
@@ -163,6 +166,7 @@ void output_view_for_each_surface(struct sway_output *output,
163 .user_iterator = iterator, 166 .user_iterator = iterator,
164 .user_data = user_data, 167 .user_data = user_data,
165 .output = output, 168 .output = output,
169 .view = view,
166 .ox = view->container->surface_x - output->lx 170 .ox = view->container->surface_x - output->lx
167 - view->geometry.x, 171 - view->geometry.x,
168 .oy = view->container->surface_y - output->ly 172 .oy = view->container->surface_y - output->ly
@@ -182,6 +186,7 @@ void output_view_for_each_popup(struct sway_output *output,
182 .user_iterator = iterator, 186 .user_iterator = iterator,
183 .user_data = user_data, 187 .user_data = user_data,
184 .output = output, 188 .output = output,
189 .view = view,
185 .ox = view->container->surface_x - output->lx 190 .ox = view->container->surface_x - output->lx
186 - view->geometry.x, 191 - view->geometry.x,
187 .oy = view->container->surface_y - output->ly 192 .oy = view->container->surface_y - output->ly
@@ -224,6 +229,7 @@ void output_layer_for_each_surface(struct sway_output *output,
224 .user_iterator = iterator, 229 .user_iterator = iterator,
225 .user_data = user_data, 230 .user_data = user_data,
226 .output = output, 231 .output = output,
232 .view = NULL,
227 .ox = popup_sx, 233 .ox = popup_sx,
228 .oy = popup_sy, 234 .oy = popup_sy,
229 .width = surface->current.width, 235 .width = surface->current.width,
@@ -291,6 +297,7 @@ static void output_for_each_surface(struct sway_output *output,
291 .user_iterator = iterator, 297 .user_iterator = iterator,
292 .user_data = user_data, 298 .user_data = user_data,
293 .output = output, 299 .output = output,
300 .view = NULL,
294 }; 301 };
295 302
296 struct sway_workspace *workspace = output_get_active_workspace(output); 303 struct sway_workspace *workspace = output_get_active_workspace(output);
@@ -401,18 +408,37 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
401 return false; 408 return false;
402} 409}
403 410
404static void send_frame_done_iterator(struct sway_output *output, 411struct send_frame_done_data {
412 struct timespec when;
413 int msec_until_refresh;
414};
415
416static void send_frame_done_iterator(struct sway_output *output, struct sway_view *view,
405 struct wlr_surface *surface, struct wlr_box *box, float rotation, 417 struct wlr_surface *surface, struct wlr_box *box, float rotation,
406 void *data) { 418 void *user_data) {
407 struct timespec *when = data; 419 int view_max_render_time = 0;
408 wlr_surface_send_frame_done(surface, when); 420 if (view != NULL) {
421 view_max_render_time = view->max_render_time;
422 }
423
424 struct send_frame_done_data *data = user_data;
425
426 int delay = data->msec_until_refresh - output->max_render_time
427 - view_max_render_time;
428
429 if (output->max_render_time == 0 || view_max_render_time == 0 || delay < 1) {
430 wlr_surface_send_frame_done(surface, &data->when);
431 } else {
432 struct sway_surface *sway_surface = surface->data;
433 wl_event_source_timer_update(sway_surface->frame_done_timer, delay);
434 }
409} 435}
410 436
411static void send_frame_done(struct sway_output *output, struct timespec *when) { 437static void send_frame_done(struct sway_output *output, struct send_frame_done_data *data) {
412 output_for_each_surface(output, send_frame_done_iterator, when); 438 output_for_each_surface(output, send_frame_done_iterator, data);
413} 439}
414 440
415static void count_surface_iterator(struct sway_output *output, 441static void count_surface_iterator(struct sway_output *output, struct sway_view *view,
416 struct wlr_surface *surface, struct wlr_box *_box, float rotation, 442 struct wlr_surface *surface, struct wlr_box *_box, float rotation,
417 void *data) { 443 void *data) {
418 size_t *n = data; 444 size_t *n = data;
@@ -533,7 +559,7 @@ int output_repaint_timer_handler(void *data) {
533 return 0; 559 return 0;
534} 560}
535 561
536static void damage_handle_frame(struct wl_listener *listener, void *data) { 562static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
537 struct sway_output *output = 563 struct sway_output *output =
538 wl_container_of(listener, output, damage_frame); 564 wl_container_of(listener, output, damage_frame);
539 if (!output->enabled || !output->wlr_output->enabled) { 565 if (!output->enabled || !output->wlr_output->enabled) {
@@ -592,9 +618,10 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) {
592 } 618 }
593 619
594 // Send frame done to all visible surfaces 620 // Send frame done to all visible surfaces
595 struct timespec now; 621 struct send_frame_done_data data = {0};
596 clock_gettime(CLOCK_MONOTONIC, &now); 622 clock_gettime(CLOCK_MONOTONIC, &data.when);
597 send_frame_done(output, &now); 623 data.msec_until_refresh = msec_until_refresh;
624 send_frame_done(output, &data);
598} 625}
599 626
600void output_damage_whole(struct sway_output *output) { 627void output_damage_whole(struct sway_output *output) {
@@ -605,7 +632,7 @@ void output_damage_whole(struct sway_output *output) {
605 } 632 }
606} 633}
607 634
608static void damage_surface_iterator(struct sway_output *output, 635static void damage_surface_iterator(struct sway_output *output, struct sway_view *view,
609 struct wlr_surface *surface, struct wlr_box *_box, float rotation, 636 struct wlr_surface *surface, struct wlr_box *_box, float rotation,
610 void *_data) { 637 void *_data) {
611 bool *data = _data; 638 bool *data = _data;
@@ -811,7 +838,7 @@ static void handle_scale(struct wl_listener *listener, void *data) {
811 update_output_manager_config(output->server); 838 update_output_manager_config(output->server);
812} 839}
813 840
814static void send_presented_iterator(struct sway_output *output, 841static void send_presented_iterator(struct sway_output *output, struct sway_view *view,
815 struct wlr_surface *surface, struct wlr_box *box, float rotation, 842 struct wlr_surface *surface, struct wlr_box *box, float rotation,
816 void *data) { 843 void *data) {
817 struct wlr_presentation_event *event = data; 844 struct wlr_presentation_event *event = data;
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 916d4eba..c432b476 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -97,7 +97,7 @@ damage_finish:
97 pixman_region32_fini(&damage); 97 pixman_region32_fini(&damage);
98} 98}
99 99
100static void render_surface_iterator(struct sway_output *output, 100static void render_surface_iterator(struct sway_output *output, struct sway_view *view,
101 struct wlr_surface *surface, struct wlr_box *_box, float rotation, 101 struct wlr_surface *surface, struct wlr_box *_box, float rotation,
102 void *_data) { 102 void *_data) {
103 struct render_data *data = _data; 103 struct render_data *data = _data;
@@ -214,11 +214,11 @@ static void render_view_toplevels(struct sway_view *view,
214 render_surface_iterator, &data); 214 render_surface_iterator, &data);
215} 215}
216 216
217static void render_popup_iterator(struct sway_output *output, 217static void render_popup_iterator(struct sway_output *output, struct sway_view *view,
218 struct wlr_surface *surface, struct wlr_box *box, float rotation, 218 struct wlr_surface *surface, struct wlr_box *box, float rotation,
219 void *data) { 219 void *data) {
220 // Render this popup's surface 220 // Render this popup's surface
221 render_surface_iterator(output, surface, box, rotation, data); 221 render_surface_iterator(output, view, surface, box, rotation, data);
222 222
223 // Render this popup's child toplevels 223 // Render this popup's child toplevels
224 output_surface_for_each_surface(output, surface, box->x, box->y, 224 output_surface_for_each_surface(output, surface, box->x, box->y,
diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c
index 41d4ce3f..853c403d 100644
--- a/sway/desktop/surface.c
+++ b/sway/desktop/surface.c
@@ -1,4 +1,6 @@
1#define _POSIX_C_SOURCE 200112L
1#include <stdlib.h> 2#include <stdlib.h>
3#include <time.h>
2#include <wlr/types/wlr_surface.h> 4#include <wlr/types/wlr_surface.h>
3#include "sway/server.h" 5#include "sway/server.h"
4#include "sway/surface.h" 6#include "sway/surface.h"
@@ -9,9 +11,21 @@ void handle_destroy(struct wl_listener *listener, void *data) {
9 surface->wlr_surface->data = NULL; 11 surface->wlr_surface->data = NULL;
10 wl_list_remove(&surface->destroy.link); 12 wl_list_remove(&surface->destroy.link);
11 13
14 wl_event_source_remove(surface->frame_done_timer);
15
12 free(surface); 16 free(surface);
13} 17}
14 18
19static int surface_frame_done_timer_handler(void *data) {
20 struct sway_surface *surface = data;
21
22 struct timespec now;
23 clock_gettime(CLOCK_MONOTONIC, &now);
24 wlr_surface_send_frame_done(surface->wlr_surface, &now);
25
26 return 0;
27}
28
15void handle_compositor_new_surface(struct wl_listener *listener, void *data) { 29void handle_compositor_new_surface(struct wl_listener *listener, void *data) {
16 struct wlr_surface *wlr_surface = data; 30 struct wlr_surface *wlr_surface = data;
17 31
@@ -21,4 +35,7 @@ void handle_compositor_new_surface(struct wl_listener *listener, void *data) {
21 35
22 surface->destroy.notify = handle_destroy; 36 surface->destroy.notify = handle_destroy;
23 wl_signal_add(&wlr_surface->events.destroy, &surface->destroy); 37 wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
38
39 surface->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop,
40 surface_frame_done_timer_handler, surface);
24} 41}
diff --git a/sway/meson.build b/sway/meson.build
index 12540154..e285c09e 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -68,6 +68,7 @@ sway_sources = files(
68 'commands/inhibit_idle.c', 68 'commands/inhibit_idle.c',
69 'commands/kill.c', 69 'commands/kill.c',
70 'commands/mark.c', 70 'commands/mark.c',
71 'commands/max_render_time.c',
71 'commands/opacity.c', 72 'commands/opacity.c',
72 'commands/include.c', 73 'commands/include.c',
73 'commands/input.c', 74 'commands/input.c',
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 01496f19..858e73c1 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -131,6 +131,9 @@ must be separated by one space. For example:
131 . Start with *max_render_time 1*. Increment by *1* if you see frame 131 . Start with *max_render_time 1*. Increment by *1* if you see frame
132 drops. 132 drops.
133 133
134 To achieve even lower latency, see the *max_render_time* surface
135 property in *sway*(5).
136
134# SEE ALSO 137# SEE ALSO
135 138
136*sway*(5) *sway-input*(5) 139*sway*(5) *sway-input*(5)
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 9119b379..52ee9d28 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -182,6 +182,22 @@ set|plus|minus <amount>
182*layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]... 182*layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...
183 Cycles the layout mode of the focused container through a list of layouts. 183 Cycles the layout mode of the focused container through a list of layouts.
184 184
185*max_render_time* off|<msec>
186 Works together with *output max_render_time* to reduce the latency even
187 further by delaying the frame callbacks sent to a surface. When set to
188 a positive number of milliseconds, delays the frame callback in such a
189 way that the surface has the specified number of milliseconds to render
190 and commit new contents before being sampled by the compositor for the
191 next presentation. See *max_render_time* in *sway-output*(5) for
192 further details.
193
194 To set this up for optimal latency:
195 . Set up *output max_render_time*.
196 . Put the target application in _full-screen_ and have it continuously
197 render something.
198 . Start by setting *max_render_time 1*. If the application drops
199 frames, increment by *1*.
200
185*move* left|right|up|down [<px> px] 201*move* left|right|up|down [<px> px]
186 Moves the focused container in the direction specified. If the container, 202 Moves the focused container in the direction specified. If the container,
187 the optional _px_ argument specifies how many pixels to move the container. 203 the optional _px_ argument specifies how many pixels to move the container.