presentation: store input timestamp in a per-commit context

This should reduce the risk of mixing up an input timestamp with the
corresponding rendered frame.
This commit is contained in:
Daniel Eklöf 2020-01-21 18:51:04 +01:00
parent 3600099b52
commit d6ea676ef2
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 42 additions and 35 deletions

View file

@ -528,12 +528,13 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
term_to_slave(term, buf, count); term_to_slave(term, buf, count);
} }
clock_gettime(
term->wl->presentation_clock_id, &term->render.input_time);
term_reset_view(term); term_reset_view(term);
selection_cancel(term); selection_cancel(term);
maybe_repeat: maybe_repeat:
clock_gettime(
term->wl->presentation_clock_id, &term->render.input_time);
if (should_repeat) if (should_repeat)
start_repeater(wayl, key - 8); start_repeater(wayl, key - 8);

View file

@ -88,63 +88,59 @@ sync_output(void *data,
{ {
} }
struct presentation_context {
struct terminal *term;
struct timeval input;
struct timeval commit;
};
static void static void
presented(void *data, presented(void *data,
struct wp_presentation_feedback *wp_presentation_feedback, struct wp_presentation_feedback *wp_presentation_feedback,
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec,
uint32_t refresh, uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) uint32_t refresh, uint32_t seq_hi, uint32_t seq_lo, uint32_t flags)
{ {
struct terminal *term = data; struct presentation_context *ctx = data;
struct terminal *term = ctx->term;
if (term->render.commit_time.tv_sec == 0 && term->render.commit_time.tv_nsec == 0) const struct timeval *input = &ctx->input;
return; const struct timeval *commit = &ctx->commit;
const struct timeval input = {
.tv_sec = term->render.input_time.tv_sec,
.tv_usec = term->render.input_time.tv_nsec / 1000,
};
const struct timeval commit = {
.tv_sec = term->render.commit_time.tv_sec,
.tv_usec = term->render.commit_time.tv_nsec / 1000,
};
const struct timeval presented = { const struct timeval presented = {
.tv_sec = (uint64_t)tv_sec_hi << 32 | tv_sec_lo, .tv_sec = (uint64_t)tv_sec_hi << 32 | tv_sec_lo,
.tv_usec = tv_nsec / 1000, .tv_usec = tv_nsec / 1000,
}; };
bool use_input = (input.tv_sec > 0 || input.tv_usec > 0) && bool use_input = (input->tv_sec > 0 || input->tv_usec > 0) &&
timercmp(&presented, &input, >); timercmp(&presented, input, >);
char msg[1024]; char msg[1024];
int chars = 0; int chars = 0;
if (use_input && timercmp(&presented, &input, <)) if (use_input && timercmp(&presented, input, <))
return; return;
else if (timercmp(&presented, &commit, <)) else if (timercmp(&presented, commit, <))
return; return;
LOG_DBG("commit: %lu s %lu µs, presented: %lu s %lu µs", LOG_DBG("commit: %lu s %lu µs, presented: %lu s %lu µs",
commit.tv_sec, commit.tv_usec, presented.tv_sec, presented.tv_usec); commit->tv_sec, commit->tv_usec, presented.tv_sec, presented.tv_usec);
if (use_input) { if (use_input) {
struct timeval diff; struct timeval diff;
timersub(&commit, &input, &diff); timersub(commit, input, &diff);
chars += snprintf(&msg[chars], sizeof(msg) - chars, chars += snprintf(&msg[chars], sizeof(msg) - chars,
"input - %lu µs -> ", diff.tv_usec); "input - %lu µs -> ", diff.tv_usec);
} }
struct timeval diff; struct timeval diff;
timersub(&presented, &commit, &diff); timersub(&presented, commit, &diff);
chars += snprintf(&msg[chars], sizeof(msg) - chars, chars += snprintf(&msg[chars], sizeof(msg) - chars,
"commit - %lu µs -> ", diff.tv_usec); "commit - %lu µs -> ", diff.tv_usec);
if (use_input) { if (use_input) {
assert(timercmp(&presented, &input, >)); assert(timercmp(&presented, input, >));
timersub(&presented, &input, &diff); timersub(&presented, input, &diff);
} else { } else {
assert(timercmp(&presented, &commit, >)); assert(timercmp(&presented, commit, >));
timersub(&presented, &commit, &diff); timersub(&presented, commit, &diff);
} }
chars += snprintf(&msg[chars], sizeof(msg) - chars, chars += snprintf(&msg[chars], sizeof(msg) - chars,
@ -176,17 +172,15 @@ presented(void *data,
#undef _log_fmt #undef _log_fmt
wp_presentation_feedback_destroy(wp_presentation_feedback); wp_presentation_feedback_destroy(wp_presentation_feedback);
memset(&term->render.input_time, 0, sizeof(term->render.input_time)); free(ctx);
memset(&term->render.commit_time, 0, sizeof(term->render.commit_time));
} }
static void static void
discarded(void *data, struct wp_presentation_feedback *wp_presentation_feedback) discarded(void *data, struct wp_presentation_feedback *wp_presentation_feedback)
{ {
struct terminal *term = data; struct presentation_context *ctx = data;
wp_presentation_feedback_destroy(wp_presentation_feedback); wp_presentation_feedback_destroy(wp_presentation_feedback);
memset(&term->render.input_time, 0, sizeof(term->render.input_time)); free(ctx);
memset(&term->render.commit_time, 0, sizeof(term->render.commit_time));
} }
static const struct wp_presentation_feedback_listener presentation_feedback_listener = { static const struct wp_presentation_feedback_listener presentation_feedback_listener = {
@ -842,7 +836,8 @@ grid_render(struct terminal *term)
wl_surface_set_buffer_scale(term->window->surface, term->scale); wl_surface_set_buffer_scale(term->window->surface, term->scale);
if (term->wl->presentation != NULL && term->render.presentation_timings) { if (term->wl->presentation != NULL && term->render.presentation_timings) {
clock_gettime(term->wl->presentation_clock_id, &term->render.commit_time); struct timespec commit_time;
clock_gettime(term->wl->presentation_clock_id, &commit_time);
struct wp_presentation_feedback *feedback = wp_presentation_feedback( struct wp_presentation_feedback *feedback = wp_presentation_feedback(
term->wl->presentation, term->window->surface); term->wl->presentation, term->window->surface);
@ -850,8 +845,20 @@ grid_render(struct terminal *term)
if (feedback == NULL) { if (feedback == NULL) {
LOG_WARN("failed to create presentation feedback"); LOG_WARN("failed to create presentation feedback");
} else { } else {
struct presentation_context *ctx = malloc(sizeof(*ctx));
*ctx = (struct presentation_context){
.term = term,
.input.tv_sec = term->render.input_time.tv_sec,
.input.tv_usec = term->render.input_time.tv_nsec / 1000,
.commit.tv_sec = commit_time.tv_sec,
.commit.tv_usec = commit_time.tv_nsec / 1000,
};
wp_presentation_feedback_add_listener( wp_presentation_feedback_add_listener(
feedback, &presentation_feedback_listener, term); feedback, &presentation_feedback_listener, ctx);
term->render.input_time.tv_sec = 0;
term->render.input_time.tv_nsec = 0;
} }
} }

View file

@ -331,7 +331,6 @@ struct terminal {
bool presentation_timings; bool presentation_timings;
struct timespec input_time; struct timespec input_time;
struct timespec commit_time;
} render; } render;
/* Temporary: for FDM */ /* Temporary: for FDM */