mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
add wl_surface.frame based frame scheduler
This commit is contained in:
parent
c515813fd6
commit
9b3588e97c
4 changed files with 86 additions and 1 deletions
|
|
@ -563,6 +563,11 @@ bool wlr_backend_is_wl(struct wlr_backend *b) {
|
|||
return b->impl == &backend_impl;
|
||||
}
|
||||
|
||||
bool wlr_wl_backend_has_presentation_time(struct wlr_backend *wlr_backend) {
|
||||
struct wlr_wl_backend *backend = get_wl_backend_from_backend(wlr_backend);
|
||||
return backend->presentation != NULL;
|
||||
}
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_wl_backend *wl =
|
||||
wl_container_of(listener, wl, local_display_destroy);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ struct wlr_output *wlr_wl_output_create_from_surface(struct wlr_backend *backend
|
|||
*/
|
||||
bool wlr_backend_is_wl(struct wlr_backend *backend);
|
||||
|
||||
/**
|
||||
* Check whether the Wayland server advertises the wp_presentation protocol.
|
||||
*/
|
||||
bool wlr_wl_backend_has_presentation_time(struct wlr_backend *backend);
|
||||
|
||||
/**
|
||||
* Check whether the provided input device is a Wayland input device.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ struct wlr_frame_scheduler {
|
|||
* the render loop, it emits the frame signal when the compositor's event loop is idle.
|
||||
*/
|
||||
struct wlr_frame_scheduler *wlr_present_idle_scheduler_create(struct wlr_output *output);
|
||||
/*
|
||||
* The Wayland-idle scheduler maintains a render loop based on wl_surface.frame callbacks. To wake
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Creates an appropriate frame scheduler for the given output's backend capabilities.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/backend/wayland.h>
|
||||
#include <wlr/interfaces/wlr_frame_scheduler.h>
|
||||
#include <wlr/types/wlr_frame_scheduler.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
void wlr_frame_scheduler_schedule_frame(struct wlr_frame_scheduler *scheduler) {
|
||||
scheduler->impl->schedule_frame(scheduler);
|
||||
|
|
@ -142,7 +146,73 @@ struct wlr_frame_scheduler *wlr_present_idle_scheduler_create(struct wlr_output
|
|||
return &scheduler->base.base;
|
||||
}
|
||||
|
||||
// This scheduler builds on idle_frame_scheduler and uses Wayland's frame callbacks for driving the
|
||||
// render loop.
|
||||
struct wl_idle_scheduler {
|
||||
struct idle_frame_scheduler base;
|
||||
struct wl_callback *frame;
|
||||
struct wl_listener precommit;
|
||||
};
|
||||
|
||||
static void wl_idle_scheduler_destroy(struct wlr_frame_scheduler *wlr_scheduler) {
|
||||
struct wl_idle_scheduler *scheduler = wl_container_of(wlr_scheduler, scheduler, base.base);
|
||||
idle_frame_scheduler_finish(&scheduler->base);
|
||||
wl_callback_destroy(scheduler->frame);
|
||||
free(scheduler);
|
||||
}
|
||||
|
||||
static void wl_idle_scheduler_handle_frame(void *data, struct wl_callback *cb, uint32_t time) {
|
||||
struct wl_idle_scheduler *scheduler = data;
|
||||
assert(scheduler->frame == cb);
|
||||
scheduler->base.frame_pending = false;
|
||||
idle_frame_scheduler_emit_frame(&scheduler->base);
|
||||
}
|
||||
|
||||
struct wl_callback_listener wl_idle_scheduler_frame_listener = {
|
||||
.done = wl_idle_scheduler_handle_frame,
|
||||
};
|
||||
|
||||
static void wl_idle_scheduler_handle_precommit(struct wl_listener *listener, void *data) {
|
||||
struct wl_idle_scheduler *scheduler = wl_container_of(listener, scheduler, precommit);
|
||||
struct wlr_output_event_precommit *precommit = data;
|
||||
if (!(precommit->state->committed & (WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_LAYERS))) {
|
||||
return;
|
||||
}
|
||||
idle_frame_scheduler_set_frame_pending(&scheduler->base);
|
||||
if (scheduler->frame != NULL) {
|
||||
wl_callback_destroy(scheduler->frame);
|
||||
}
|
||||
struct wl_surface *surface = wlr_wl_output_get_surface(scheduler->base.base.output);
|
||||
scheduler->frame = wl_surface_frame(surface);
|
||||
wl_callback_add_listener(scheduler->frame, &wl_idle_scheduler_frame_listener, scheduler);
|
||||
}
|
||||
|
||||
struct wlr_frame_scheduler_impl wl_idle_scheduler_impl = {
|
||||
.schedule_frame = idle_frame_scheduler_schedule_frame,
|
||||
.destroy = wl_idle_scheduler_destroy,
|
||||
};
|
||||
|
||||
static struct wlr_frame_scheduler *wl_idle_scheduler_create(struct wlr_output *output) {
|
||||
if (!wlr_output_is_wl(output)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_idle_scheduler *scheduler = calloc(1, sizeof(struct wl_idle_scheduler));
|
||||
if (!scheduler) {
|
||||
return NULL;
|
||||
}
|
||||
frame_scheduler_init(&scheduler->base.base, &wl_idle_scheduler_impl, output);
|
||||
scheduler->precommit.notify = wl_idle_scheduler_handle_precommit;
|
||||
wl_signal_add(&output->events.precommit, &scheduler->precommit);
|
||||
|
||||
return &scheduler->base.base;
|
||||
}
|
||||
|
||||
struct wlr_frame_scheduler *wlr_frame_scheduler_autocreate(struct wlr_output *output) {
|
||||
// TODO: check for presentation-time in wayland backend and work with frame cbs if absent
|
||||
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_idle_scheduler_create(output);
|
||||
}
|
||||
|
||||
return wlr_present_idle_scheduler_create(output);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue