mirror of
https://github.com/swaywm/sway.git
synced 2026-04-26 06:46:26 -04:00
Add timespec helpers
Borrow timespec helpers from Weston [1]. We'll re-use these helpers for
adaptive sync in a future commit.
Rename refresh_nsec to next_refresh_nsec, because this value only
applies to the next output presentation.
[1]: 467e6b9883/shared/timespec-util.h
This commit is contained in:
parent
c0811fcf87
commit
a5fbffb40d
4 changed files with 56 additions and 21 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <time.h>
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -102,3 +103,40 @@ bool sway_set_cloexec(int fd, bool cloexec) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int64_t NSEC_PER_SEC = 1000000000;
|
||||
|
||||
void timespec_sub(struct timespec *r, const struct timespec *a,
|
||||
const struct timespec *b) {
|
||||
r->tv_sec = a->tv_sec - b->tv_sec;
|
||||
r->tv_nsec = a->tv_nsec - b->tv_nsec;
|
||||
if (r->tv_nsec < 0) {
|
||||
r->tv_sec--;
|
||||
r->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t timespec_sub_to_nsec(const struct timespec *a,
|
||||
const struct timespec *b) {
|
||||
struct timespec r;
|
||||
timespec_sub(&r, a, b);
|
||||
return timespec_to_nsec(&r);
|
||||
}
|
||||
|
||||
void timespec_add_nsec(struct timespec *r, const struct timespec *a,
|
||||
int64_t nsec) {
|
||||
r->tv_sec = a->tv_sec + (nsec / NSEC_PER_SEC);
|
||||
r->tv_nsec = a->tv_nsec + (nsec % NSEC_PER_SEC);
|
||||
|
||||
if (r->tv_nsec >= NSEC_PER_SEC) {
|
||||
r->tv_sec++;
|
||||
r->tv_nsec -= NSEC_PER_SEC;
|
||||
} else if (r->tv_nsec < 0) {
|
||||
r->tv_sec--;
|
||||
r->tv_nsec += NSEC_PER_SEC;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t timespec_to_nsec(const struct timespec *t) {
|
||||
return (int64_t)t->tv_sec * NSEC_PER_SEC + t->tv_nsec;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ struct sway_output {
|
|||
} events;
|
||||
|
||||
struct timespec last_presentation;
|
||||
uint32_t refresh_nsec;
|
||||
uint32_t next_refresh_nsec;
|
||||
int max_render_time; // In milliseconds
|
||||
struct wl_event_source *repaint_timer;
|
||||
bool surface_needs_frame;
|
||||
|
|
|
|||
|
|
@ -37,4 +37,13 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
|
|||
|
||||
bool sway_set_cloexec(int fd, bool cloexec);
|
||||
|
||||
struct timespec;
|
||||
|
||||
void timespec_sub(struct timespec *r, const struct timespec *a,
|
||||
const struct timespec *b);
|
||||
int64_t timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b);
|
||||
void timespec_add_nsec(struct timespec *r, const struct timespec *a,
|
||||
int64_t nsec);
|
||||
int64_t timespec_to_nsec(const struct timespec *t);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "util.h"
|
||||
|
||||
struct sway_output *output_by_name_or_id(const char *name_or_id) {
|
||||
for (int i = 0; i < root->outputs->length; ++i) {
|
||||
|
|
@ -590,28 +591,15 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
|
|||
= wlr_backend_get_presentation_clock(server.backend);
|
||||
clock_gettime(presentation_clock, &now);
|
||||
|
||||
const long NSEC_IN_SECONDS = 1000000000;
|
||||
struct timespec predicted_refresh = output->last_presentation;
|
||||
predicted_refresh.tv_nsec += output->refresh_nsec % NSEC_IN_SECONDS;
|
||||
predicted_refresh.tv_sec += output->refresh_nsec / NSEC_IN_SECONDS;
|
||||
if (predicted_refresh.tv_nsec >= NSEC_IN_SECONDS) {
|
||||
predicted_refresh.tv_sec += 1;
|
||||
predicted_refresh.tv_nsec -= NSEC_IN_SECONDS;
|
||||
}
|
||||
struct timespec predicted_refresh;
|
||||
timespec_add_nsec(&predicted_refresh, &output->last_presentation,
|
||||
output->next_refresh_nsec);
|
||||
|
||||
// If the predicted refresh time is before the current time then
|
||||
// there's no point in delaying.
|
||||
//
|
||||
// We only check tv_sec because if the predicted refresh time is less
|
||||
// than a second before the current time, then msec_until_refresh will
|
||||
// end up slightly below zero, which will effectively disable the delay
|
||||
// without potential disastrous negative overflows that could occur if
|
||||
// tv_sec was not checked.
|
||||
if (predicted_refresh.tv_sec >= now.tv_sec) {
|
||||
long nsec_until_refresh
|
||||
= (predicted_refresh.tv_sec - now.tv_sec) * NSEC_IN_SECONDS
|
||||
+ (predicted_refresh.tv_nsec - now.tv_nsec);
|
||||
|
||||
int64_t nsec_until_refresh =
|
||||
timespec_sub_to_nsec(&predicted_refresh, &now);
|
||||
if (nsec_until_refresh >= 0) {
|
||||
// We want msec_until_refresh to be conservative, that is, floored.
|
||||
// If we have 7.9 msec until refresh, we better compute the delay
|
||||
// as if we had only 7 msec, so that we don't accidentally delay
|
||||
|
|
@ -862,7 +850,7 @@ static void handle_present(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
|
||||
output->last_presentation = *output_event->when;
|
||||
output->refresh_nsec = output_event->refresh;
|
||||
output->next_refresh_nsec = output_event->refresh;
|
||||
}
|
||||
|
||||
void handle_new_output(struct wl_listener *listener, void *data) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue