output: Add support for max_render_time auto

When set to auto, sway will use the new predictive frame scheduler.
This commit is contained in:
Kenny Levinsen 2026-04-06 16:42:19 +00:00
parent 2ae7af1844
commit 856e4f108b
4 changed files with 17 additions and 18 deletions

View file

@ -19,6 +19,8 @@ struct sway_output_state {
struct sway_workspace *active_workspace;
};
#define MAX_RENDER_TIME_AUTO -2
struct sway_output {
struct sway_node node;
@ -66,7 +68,7 @@ struct sway_output {
struct wlr_color_transform *color_transform;
struct wlr_ext_workspace_group_handle_v1 *ext_workspace_group;
int max_render_time; // In milliseconds
int max_render_time;
bool allow_tearing;
bool hdr;

View file

@ -1,6 +1,7 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *output_cmd_max_render_time(int argc, char **argv) {
if (!config->handler_context.output_config) {
@ -13,6 +14,8 @@ struct cmd_results *output_cmd_max_render_time(int argc, char **argv) {
int max_render_time;
if (!strcmp(*argv, "off")) {
max_render_time = 0;
} else if (!strcmp(*argv, "auto")) {
max_render_time = MAX_RENDER_TIME_AUTO;
} else {
char *end;
max_render_time = strtol(*argv, &end, 10);

View file

@ -684,8 +684,11 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
}
output->color_transform = config_applied->color_transform;
output_set_max_render_time(output,
oc && oc->max_render_time > 0 ? oc->max_render_time : 0);
int max_render_time = 0;
if (oc && (oc->max_render_time > 0 || oc->max_render_time == MAX_RENDER_TIME_AUTO)) {
max_render_time = oc->max_render_time;
}
output_set_max_render_time(output, max_render_time);
output->allow_tearing = oc && oc->allow_tearing > 0;
output->hdr = applied->image_description != NULL;

View file

@ -317,7 +317,6 @@ struct sway_timer_frame_scheduler {
struct wl_event_source *timer;
bool frame_pending;
bool needs_frame;
struct wl_listener present;
};
@ -333,25 +332,15 @@ static void timed_frame_scheduler_destroy(struct wlr_frame_scheduler *wlr_schedu
free(scheduler);
}
static void timed_frame_scheduler_trigger_frame(
struct sway_timer_frame_scheduler *scheduler) {
if (!scheduler->needs_frame) {
return;
}
scheduler->needs_frame = false;
wl_signal_emit_mutable(&scheduler->base.events.frame, NULL);
}
static void timed_frame_scheduler_handle_idle(void *data) {
struct sway_timer_frame_scheduler *scheduler = data;
scheduler->idle = NULL;
timed_frame_scheduler_trigger_frame(scheduler);
wlr_frame_scheduler_emit_frame(&scheduler->base);
}
static void timed_frame_scheduler_schedule_frame(struct wlr_frame_scheduler *wlr_scheduler) {
struct sway_timer_frame_scheduler *scheduler =
wl_container_of(wlr_scheduler, scheduler, base);
scheduler->needs_frame = true;
if (scheduler->idle != NULL || scheduler->frame_pending) {
return;
}
@ -367,7 +356,7 @@ static const struct wlr_frame_scheduler_impl timed_frame_scheduler_impl = {
static int timed_frame_scheduler_handle_timer(void *data) {
struct sway_timer_frame_scheduler *scheduler = data;
scheduler->frame_pending = false;
timed_frame_scheduler_trigger_frame(scheduler);
wlr_frame_scheduler_emit_frame(&scheduler->base);
return 0;
}
@ -393,7 +382,7 @@ static void timed_frame_scheduler_handle_present(struct wl_listener *listener, v
// If the delay is less than 1 millisecond (which is the least we can wait)
// then just render right away.
if (delay < 1) {
timed_frame_scheduler_trigger_frame(scheduler);
wlr_frame_scheduler_emit_frame(&scheduler->base);
} else {
scheduler->frame_pending = true;
wl_event_source_timer_update(scheduler->timer, delay);
@ -471,7 +460,9 @@ void output_set_max_render_time(struct sway_output *output, int max_render_time)
output->max_render_time = max_render_time;
struct wlr_frame_scheduler *scheduler;
if (max_render_time != 0) {
if (max_render_time == MAX_RENDER_TIME_AUTO) {
scheduler = wlr_predictive_frame_scheduler_create(output->wlr_output);
} else if (max_render_time > 0) {
scheduler = timed_frame_scheduler_create(output->wlr_output, max_render_time);
} else {
scheduler = wlr_frame_scheduler_autocreate(output->wlr_output);