diff options
Diffstat (limited to 'src/common/backend.c')
| -rw-r--r-- | src/common/backend.c | 136 |
1 files changed, 98 insertions, 38 deletions
diff --git a/src/common/backend.c b/src/common/backend.c index ad9e218..9910e08 100644 --- a/src/common/backend.c +++ b/src/common/backend.c @@ -22,8 +22,38 @@ static const struct yasl_private_backend_ops *backend_ops(enum yasl_private_back } } +/* The display drives the loop it runs on; see struct yasl_private_loop_driver. */ +static bool driver_prepare(void *ud) +{ + struct yasl_private_display *d = ud; + bool ready = d->ops->display_prepare(d); + /* Readiness the backends cannot see: events already queued, an error to + * report, or an owed REFRESH. */ + return ready || yasl_private_events_pending(d) || yasl_private_events_error(d) || + (d->pending && d->pending(d)); +} + +static int driver_wait(void *ud, int timeout_ms) +{ + struct yasl_private_display *d = ud; + return d->ops->display_wait(d, timeout_ms); +} + +static void driver_check(void *ud) +{ + struct yasl_private_display *d = ud; + d->ops->display_check(d); +} + +static void driver_deliver(void *ud) +{ + struct yasl_private_display *d = ud; + if (d->deliver) + d->deliver(d); +} + static struct yasl_private_display *open_backend(enum yasl_private_backend backend, - struct yasl_private_loop *loop, const struct yasl_private_display_spec *spec) + struct yasl_loop *loop, const struct yasl_private_display_spec *spec) { const struct yasl_private_backend_ops *ops = backend_ops(backend); if (!ops) { @@ -33,18 +63,26 @@ static struct yasl_private_display *open_backend(enum yasl_private_backend backe errno = 0; struct yasl_private_display *d = ops->display_open(loop, spec); if (!d && !errno) errno = ENODEV; - if (d) { - if (!yasl_private_events_open(d)) { - int error = errno; - ops->display_close(d); - errno = error; - return NULL; - } + if (!d) + return NULL; + struct yasl_private_loop_driver driver = { + .prepare = driver_prepare, + .wait = ops->display_wait ? driver_wait : NULL, + .check = driver_check, + .deliver = driver_deliver, + .ud = d, + }; + if (!yasl_private_events_open(d) || !yasl_private_loop_set_driver(d->loop, &driver)) { + int error = errno; + yasl_private_events_close(d); + ops->display_close(d); + errno = error; + return NULL; } return d; } -struct yasl_private_display *yasl_private_display_open(struct yasl_private_loop *loop, +struct yasl_private_display *yasl_private_display_open(struct yasl_loop *loop, const struct yasl_private_display_spec *spec) { enum yasl_private_backend backend = spec ? spec->backend : YASL_PRIVATE_BACKEND_AUTO; @@ -78,6 +116,7 @@ void yasl_private_display_close(struct yasl_private_display *d) { if (!d || !d->ops->display_close) return; + yasl_private_loop_set_driver(d->loop, NULL); yasl_private_events_close(d); d->ops->display_close(d); } @@ -89,27 +128,6 @@ uint32_t yasl_private_display_caps(const struct yasl_private_display *d) return d->ops->display_caps(d); } -int yasl_private_display_dispatch(struct yasl_private_display *d, int timeout_ms) -{ - if (!d) { - errno = EINVAL; - return -1; - } - if (!d->ops->display_dispatch_timeout) { - errno = ENOTSUP; - return -1; - } - int queue_error = yasl_private_events_error(d); - if (queue_error) { errno = queue_error; return -1; } - if (yasl_private_events_pending(d)) timeout_ms = 0; - errno = 0; - int result = d->ops->display_dispatch_timeout(d, timeout_ms); - queue_error = yasl_private_events_error(d); - if (queue_error) { errno = queue_error; return -1; } - if (result < 0 && !errno) errno = EIO; - return result; -} - void yasl_private_display_flush(struct yasl_private_display *d) { if (!d || !d->ops->display_flush) @@ -317,7 +335,10 @@ bool yasl_private_surface_present(struct yasl_surface *s, const struct yasl_priv }; } } - return s->display->ops->surface_present(s, fb, &clipped); + if (!s->display->ops->surface_present(s, fb, &clipped)) + return false; + atomic_store(&s->presented_ns, yasl_private_loop_now_ns()); + return true; } bool yasl_private_surface_read_pixels(struct yasl_surface *s, uint32_t *out, size_t cap, @@ -473,10 +494,10 @@ bool yasl_private_surface_place_under_pointer(struct yasl_surface *s, struct yas void yasl_private_surface_clear_timers(struct yasl_surface *s) { if (!s || !s->timers) return; - struct yasl_private_loop *loop = s->display ? s->display->loop : NULL; + struct yasl_loop *loop = s->display ? s->display->loop : NULL; for (int i = 0; i < s->timer_count; i++) { if (loop && s->timers[i]) { - yasl_private_loop_del_timer(loop, s->timers[i]); + yasl_loop_del_timer(loop, s->timers[i]); } } free(s->timers); @@ -491,7 +512,7 @@ yasl_private_timer_id yasl_private_surface_add_timer(struct yasl_surface *s, uin if (!s || !s->display || !s->display->loop || !cb || interval_ns == 0) return 0; - yasl_private_timer_id id = yasl_private_loop_add_timer(s->display->loop, interval_ns, cb, ud); + yasl_private_timer_id id = yasl_loop_add_timer(s->display->loop, interval_ns, cb, ud); if (!id) return 0; /* A one-shot timer retires itself in the loop. Drop retired ids before @@ -507,7 +528,7 @@ yasl_private_timer_id yasl_private_surface_add_timer(struct yasl_surface *s, uin int new_cap = s->timer_capacity ? s->timer_capacity * 2 : 4; yasl_private_timer_id *nt = realloc(s->timers, (size_t)new_cap * sizeof(*nt)); if (!nt) { - yasl_private_loop_del_timer(s->display->loop, id); + yasl_loop_del_timer(s->display->loop, id); return 0; } s->timers = nt; @@ -523,13 +544,13 @@ bool yasl_private_surface_del_timer(struct yasl_surface *s, yasl_private_timer_i for (int i = 0; i < s->timer_count; i++) { if (s->timers[i] == id) { s->timers[i] = s->timers[--s->timer_count]; - return s->display && yasl_private_loop_del_timer(s->display->loop, id); + return s->display && yasl_loop_del_timer(s->display->loop, id); } } return false; } -struct yasl_private_loop *yasl_private_display_loop(struct yasl_private_display *d) +struct yasl_loop *yasl_private_display_loop(struct yasl_private_display *d) { return d ? d->loop : NULL; } @@ -560,7 +581,46 @@ void yasl_private_surface_request_frame(struct yasl_surface *s) { if (!s) return; yasl_private_surface_schedule_redraw(s); - if (s->display->loop) yasl_private_loop_kick(s->display->loop); + yasl_private_loop_wake(s->display->loop); +} + +void yasl_private_surface_notify_frame_shown(struct yasl_surface *s) +{ + if (!s || !s->frame_requested) + return; + s->frame_requested = false; + s->refresh_owed = true; +} + +static uint64_t frame_interval_done(void *ud, yasl_private_timer_id id, uint64_t interval_ns) +{ + (void)id; (void)interval_ns; + yasl_private_surface_notify_frame_shown(ud); + return 0; +} + +bool yasl_private_surface_request_shown_frame(struct yasl_surface *s) +{ + s->frame_requested = true; + const struct yasl_private_backend_ops *ops = s->display->ops; + if (ops->surface_frame_in_flight) { + if (!ops->surface_frame_in_flight(s)) + yasl_private_surface_notify_frame_shown(s); + return true; + } + /* No frame signal: one frame per refresh interval since the last present. */ + if (yasl_private_loop_timer_armed(s->display->loop, s->frame_timer)) + return true; + double refresh = yasl_private_surface_timing(s).refresh_ns; + uint64_t interval = refresh >= 1000000.0 && refresh <= 1000000000.0 ? (uint64_t)refresh : 16666667; + uint64_t presented = atomic_load(&s->presented_ns); + uint64_t since = yasl_private_loop_now_ns() - presented; + if (!presented || since >= interval) { + yasl_private_surface_notify_frame_shown(s); + return true; + } + s->frame_timer = yasl_private_surface_add_timer(s, interval - since, frame_interval_done, s); + return s->frame_timer != 0; } static uint64_t pacing_tick(void *ud, yasl_private_timer_id id, uint64_t interval) |
