mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-14 08:22:25 -04:00
Add interval frame scheduler
Headless present events aren't suitable for the present scheduler. This new scheduler is a good place for headless' existing frame logic to go, so move it into there. With this decoupling, there's nothing tying the scheduler to the headless backend, hence the generic name.
This commit is contained in:
parent
ad145dce86
commit
ee100e2586
2 changed files with 77 additions and 0 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#include <assert.h>
|
||||
#include <backend/headless.h>
|
||||
#include <stdlib.h>
|
||||
#include <types/wlr_output.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
|
@ -215,11 +216,82 @@ static struct wlr_frame_scheduler *wl_scheduler_create(struct wlr_output *output
|
|||
return &scheduler->base.base;
|
||||
}
|
||||
|
||||
#define DEFAULT_REFRESH (60 * 1000) // 60 Hz in mHz
|
||||
|
||||
struct interval_scheduler {
|
||||
struct idle_frame_scheduler base;
|
||||
struct wl_event_source *frame_timer;
|
||||
struct wl_listener commit;
|
||||
|
||||
int32_t frame_delay;
|
||||
};
|
||||
|
||||
static void interval_scheduler_destroy(struct wlr_frame_scheduler *wlr_scheduler) {
|
||||
struct interval_scheduler *scheduler = wl_container_of(wlr_scheduler, scheduler, base.base);
|
||||
idle_frame_scheduler_finish(&scheduler->base);
|
||||
wl_event_source_remove(scheduler->frame_timer);
|
||||
wl_list_remove(&scheduler->commit.link);
|
||||
free(scheduler);
|
||||
}
|
||||
|
||||
static void interval_scheduler_handle_commit(struct wl_listener *listener, void *data) {
|
||||
struct interval_scheduler *scheduler = wl_container_of(listener, scheduler, commit);
|
||||
struct wlr_output_event_commit *commit = data;
|
||||
struct wlr_output *output = commit->output;
|
||||
if (commit->state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||
int32_t refresh = output->refresh ? output->refresh : DEFAULT_REFRESH;
|
||||
scheduler->frame_delay = 1000 * 1000 / refresh;
|
||||
}
|
||||
|
||||
if (output->enabled) {
|
||||
assert(scheduler->frame_delay != 0);
|
||||
wl_event_source_timer_update(scheduler->frame_timer, scheduler->frame_delay);
|
||||
idle_frame_scheduler_set_frame_pending(&scheduler->base);
|
||||
}
|
||||
}
|
||||
|
||||
static int interval_scheduler_handle_timer(void *data) {
|
||||
struct interval_scheduler *scheduler = data;
|
||||
idle_frame_scheduler_emit_frame(&scheduler->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wlr_frame_scheduler_impl interval_scheduler_impl = {
|
||||
.schedule_frame = idle_frame_scheduler_schedule_frame,
|
||||
.destroy = interval_scheduler_destroy,
|
||||
};
|
||||
|
||||
struct wlr_frame_scheduler *wlr_interval_scheduler_create(struct wlr_output *output) {
|
||||
if (!wlr_output_is_headless(output)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct interval_scheduler *scheduler = calloc(1, sizeof(*scheduler));
|
||||
if (!scheduler) {
|
||||
return NULL;
|
||||
}
|
||||
wlr_frame_scheduler_init(&scheduler->base.base, &interval_scheduler_impl, output);
|
||||
|
||||
scheduler->frame_delay = 1000 * 1000 / DEFAULT_REFRESH;
|
||||
|
||||
scheduler->frame_timer = wl_event_loop_add_timer(output->event_loop,
|
||||
interval_scheduler_handle_timer, scheduler);
|
||||
|
||||
scheduler->commit.notify = interval_scheduler_handle_commit;
|
||||
wl_signal_add(&output->events.commit, &scheduler->commit);
|
||||
|
||||
return &scheduler->base.base;
|
||||
}
|
||||
|
||||
struct wlr_frame_scheduler *wlr_frame_scheduler_autocreate(struct wlr_output *output) {
|
||||
if (wlr_output_is_wl(output) && !wlr_wl_backend_has_presentation_time(output->backend)) {
|
||||
wlr_log(WLR_INFO, "wp_presentation not available, falling back to frame callbacks");
|
||||
return wl_scheduler_create(output);
|
||||
}
|
||||
|
||||
if (wlr_output_is_headless(output)) {
|
||||
return wlr_interval_scheduler_create(output);
|
||||
}
|
||||
|
||||
return wlr_present_scheduler_create(output);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue