From f78bffa4ab0436468901ee677aa8ae6eb3f567dd Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 24 Sep 2022 15:17:14 +0000 Subject: [PATCH 1/4] sway/desktop: Implement dynamic max_render_time --- include/sway/output.h | 8 ++++++ sway/desktop/output.c | 13 +++++++-- sway/desktop/render.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index d72bf1b21..42c0e79bb 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -55,6 +55,14 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + + struct timespec render_begin_time; + struct wlr_render_timestamp *render_end_ts; + + int auto_max_render_time; // in milliseconds + // TODO: Make this adjustable: + uint8_t render_time_window[60]; + int render_time_window_index; }; struct sway_output_non_desktop { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3f3f9494a..d2c425831 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -586,7 +586,14 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) { // delaying both output rendering and surface frame callbacks. int msec_until_refresh = 0; - if (output->max_render_time != 0) { + int max_render_time = 0; + if (output->max_render_time == -1) { + max_render_time = output->auto_max_render_time; + } else if (output->max_render_time != 0) { + max_render_time = output->max_render_time; + } + + if (max_render_time != 0) { struct timespec now; clockid_t presentation_clock = wlr_backend_get_presentation_clock(server.backend); @@ -622,7 +629,7 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) { } } - int delay = msec_until_refresh - output->max_render_time; + int delay = msec_until_refresh - max_render_time; // If the delay is less than 1 millisecond (which is the least we can wait) // then just render right away. @@ -780,6 +787,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_server *server = output->server; output_begin_destroy(output); + wlr_render_timestamp_destroy(output->render_end_ts); + if (output->enabled) { output_disable(output); } diff --git a/sway/desktop/render.c b/sway/desktop/render.c index ed9ad4906..6504ede8f 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -1024,6 +1024,59 @@ static void render_seatops(struct sway_output *output, } } +uint8_t aggregate_render_times(struct sway_output *output, uint8_t in) +{ + int len = sizeof(output->render_time_window); + + int i = output->render_time_window_index++; + if (output->render_time_window_index >= len) { + output->render_time_window_index = 0; + } + output->render_time_window[i] = in; + + uint8_t max = 0; + for (int i = 0; i < len; ++i) { + uint8_t t = output->render_time_window[i]; + if (t > max) { + max = t; + } + } + + return max; +} + +static void calculate_max_render_time(struct sway_output *output) +{ + struct timespec ts; + if (!wlr_render_timestamp_get_time(output->render_end_ts, &ts)) { + return; + } + + uint64_t end_time_us = ts.tv_sec * UINT64_C(1000000) + + ts.tv_nsec / UINT64_C(1000); + + uint64_t begin_time_us = + output->render_begin_time.tv_sec * UINT64_C(1000000) + + output->render_begin_time.tv_nsec / UINT64_C(1000); + + if (begin_time_us > end_time_us) { + // rollover + return; + } + + uint64_t duration_us = end_time_us - begin_time_us; + + int dt_ms = ceil(duration_us / 1e3); + int max = aggregate_render_times(output, dt_ms); + + if (max != output->auto_max_render_time) { + output->auto_max_render_time = max; + + sway_log(SWAY_DEBUG, + "Adjusted output max_render_time to %d ms", max); + } +} + void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -1039,7 +1092,14 @@ void output_render(struct sway_output *output, struct timespec *when, fullscreen_con = workspace->current.fullscreen; } + if (output->max_render_time == -1 && output->render_end_ts) { + calculate_max_render_time(output); + wlr_render_timestamp_destroy(output->render_end_ts); + output->render_end_ts = NULL; + } + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + wlr_renderer_get_time(renderer, &output->render_begin_time); if (debug.damage == DAMAGE_RERENDER) { int width, height; @@ -1176,6 +1236,7 @@ render_overlay: renderer_end: wlr_renderer_scissor(renderer, NULL); wlr_output_render_software_cursors(wlr_output, damage); + output->render_end_ts = wlr_renderer_create_timestamp(renderer); wlr_renderer_end(renderer); int width, height; From aa2a2b8ce1e51abfe2fe88883fde0665310493b5 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 24 Sep 2022 15:20:07 +0000 Subject: [PATCH 2/4] swaymsg: Display automatic max_render_time --- swaymsg/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index c4e2b0bfa..c32f371b9 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -249,8 +249,15 @@ static void pretty_print_output(json_object *o) { ); int max_render_time_int = json_object_get_int(max_render_time); + printf(" Max render time: "); - printf(max_render_time_int == 0 ? "off\n" : "%d ms\n", max_render_time_int); + if (max_render_time_int == 0) { + printf("off\n"); + } else if (max_render_time_int > 0) { + printf("%d ms\n", max_render_time_int); + } else { + printf("%d ms (auto)\n", -max_render_time_int); + } printf(" Adaptive sync: %s\n", json_object_get_string(adaptive_sync_status)); From ccf1cc7c2daf345ee5b6777b5e9196f48bb1027c Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 24 Sep 2022 15:20:56 +0000 Subject: [PATCH 3/4] sway/ipc-json: Handle automatic max_render_time --- sway/ipc-json.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 763fb3fef..969ce9b25 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -342,7 +342,14 @@ static void ipc_json_describe_enabled_output(struct sway_output *output, json_object_object_add(object, "percent", json_object_new_double(percent)); } - json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time)); + int max_render_time; + if (output->max_render_time == -1) { + max_render_time = -output->auto_max_render_time; + } else { + max_render_time = output->max_render_time; + } + json_object_object_add(object, "max_render_time", + json_object_new_int(max_render_time)); } json_object *ipc_json_describe_disabled_output(struct sway_output *output) { From ff14df6db3dc4b2e7b65fea4dd80bfd95b87ff5d Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 24 Sep 2022 15:22:30 +0000 Subject: [PATCH 4/4] sway/config/output: Add max_render_time=auto option --- include/sway/config.h | 3 +++ sway/commands/output/max_render_time.c | 4 +++- sway/config/output.c | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 68c068462..446c24e71 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -21,6 +21,9 @@ // TODO: Refactor this shit +#define MAX_RENDER_TIME_OFF 0 +#define MAX_RENDER_TIME_AUTO -2 + /** * Describes a variable created via the `set` command. */ diff --git a/sway/commands/output/max_render_time.c b/sway/commands/output/max_render_time.c index 2d3cebe30..d45611468 100644 --- a/sway/commands/output/max_render_time.c +++ b/sway/commands/output/max_render_time.c @@ -12,7 +12,9 @@ struct cmd_results *output_cmd_max_render_time(int argc, char **argv) { int max_render_time; if (!strcmp(*argv, "off")) { - max_render_time = 0; + max_render_time = MAX_RENDER_TIME_OFF; + } else if (!strcmp(*argv, "auto")) { + max_render_time = MAX_RENDER_TIME_AUTO; } else { char *end; max_render_time = strtol(*argv, &end, 10); diff --git a/sway/config/output.c b/sway/config/output.c index 9c7082d07..5e07482ff 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -571,6 +571,10 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { sway_log(SWAY_DEBUG, "Set %s max render time to %d", oc->name, oc->max_render_time); output->max_render_time = oc->max_render_time; + } else if (oc && oc->max_render_time == MAX_RENDER_TIME_AUTO) { + sway_log(SWAY_DEBUG, "Set %s max render time to auto", + oc->name); + output->max_render_time = -1; } // Reconfigure all devices, since input config may have been applied before @@ -608,7 +612,7 @@ static void default_output_config(struct output_config *oc, struct sway_output *output = wlr_output->data; oc->subpixel = output->detected_subpixel; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - oc->max_render_time = 0; + oc->max_render_time = MAX_RENDER_TIME_OFF; } static struct output_config *get_output_config(char *identifier,