mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
add headless idle frame scheduler
Headless present events aren't suitable for the present idle scheduler. This new scheduler is a good place for headless' existing frame logic to go, so move it into there.
This commit is contained in:
parent
9b3588e97c
commit
7ecafde6fd
2 changed files with 79 additions and 0 deletions
|
|
@ -31,6 +31,12 @@ struct wlr_frame_scheduler *wlr_present_idle_scheduler_create(struct wlr_output
|
||||||
* the render loop, it emits the frame signal when the compositor's event loop is idle.
|
* the render loop, it emits the frame signal when the compositor's event loop is idle.
|
||||||
*/
|
*/
|
||||||
struct wlr_frame_scheduler *wlr_wl_idle_scheduler_create(struct wlr_output *output);
|
struct wlr_frame_scheduler *wlr_wl_idle_scheduler_create(struct wlr_output *output);
|
||||||
|
/*
|
||||||
|
* The headless-idle scheduler maintains a render loop based on the headless backend's refresh
|
||||||
|
* timer. To wake the render loop, it emits the frame signal when the compositor's event loop is
|
||||||
|
* idle.
|
||||||
|
*/
|
||||||
|
struct wlr_frame_scheduler *wlr_headless_idle_scheduler_create(struct wlr_output *output);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates an appropriate frame scheduler for the given output's backend capabilities.
|
* Creates an appropriate frame scheduler for the given output's backend capabilities.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <backend/headless.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wayland-client-protocol.h>
|
#include <wayland-client-protocol.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
|
@ -208,11 +209,83 @@ static struct wlr_frame_scheduler *wl_idle_scheduler_create(struct wlr_output *o
|
||||||
return &scheduler->base.base;
|
return &scheduler->base.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HEADLESS_DEFAULT_REFRESH (60 * 1000) // 60 Hz
|
||||||
|
|
||||||
|
struct headless_idle_scheduler {
|
||||||
|
struct idle_frame_scheduler base;
|
||||||
|
struct wl_event_source *frame_timer;
|
||||||
|
struct wl_listener commit;
|
||||||
|
|
||||||
|
int32_t frame_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void headless_idle_scheduler_destroy(struct wlr_frame_scheduler *wlr_scheduler) {
|
||||||
|
struct headless_idle_scheduler *scheduler = wl_container_of(wlr_scheduler, scheduler, base.base);
|
||||||
|
idle_frame_scheduler_finish(&scheduler->base);
|
||||||
|
wl_event_source_remove(scheduler->frame_timer);
|
||||||
|
free(scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void headless_idle_scheduler_handle_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct headless_idle_scheduler *scheduler = wl_container_of(listener, scheduler, commit);
|
||||||
|
struct wlr_output_event_commit *commit = data;
|
||||||
|
struct wlr_output *output = commit->output;
|
||||||
|
if (commit->committed & WLR_OUTPUT_STATE_MODE) {
|
||||||
|
int32_t refresh = output->refresh ? output->refresh : HEADLESS_DEFAULT_REFRESH;
|
||||||
|
scheduler->frame_delay = 1000 * 1000 / refresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commit->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||||
|
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 headless_idle_scheduler_handle_timer(void *data) {
|
||||||
|
struct headless_idle_scheduler *scheduler = data;
|
||||||
|
scheduler->base.frame_pending = false;
|
||||||
|
idle_frame_scheduler_emit_frame(&scheduler->base);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_frame_scheduler_impl headless_idle_scheduler_impl = {
|
||||||
|
.schedule_frame = idle_frame_scheduler_schedule_frame,
|
||||||
|
.destroy = headless_idle_scheduler_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_frame_scheduler *wlr_headless_idle_scheduler_create(struct wlr_output *output) {
|
||||||
|
if (!wlr_output_is_headless(output)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct headless_idle_scheduler *scheduler = calloc(1, sizeof(struct headless_idle_scheduler));
|
||||||
|
if (!scheduler) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
frame_scheduler_init(&scheduler->base.base, &headless_idle_scheduler_impl, output);
|
||||||
|
|
||||||
|
scheduler->frame_delay = 1000 * 1000 / HEADLESS_DEFAULT_REFRESH;
|
||||||
|
|
||||||
|
struct wl_event_loop *ev = wl_display_get_event_loop(output->display);
|
||||||
|
scheduler->frame_timer = wl_event_loop_add_timer(ev, headless_idle_scheduler_handle_timer,
|
||||||
|
scheduler);
|
||||||
|
|
||||||
|
scheduler->commit.notify = headless_idle_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) {
|
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)) {
|
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");
|
wlr_log(WLR_INFO, "wp_presentation not available, falling back to frame callbacks");
|
||||||
return wl_idle_scheduler_create(output);
|
return wl_idle_scheduler_create(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wlr_output_is_headless(output)) {
|
||||||
|
return wlr_headless_idle_scheduler_create(output);
|
||||||
|
}
|
||||||
|
|
||||||
return wlr_present_idle_scheduler_create(output);
|
return wlr_present_idle_scheduler_create(output);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue