output: add presentation refresh prediction

This commit is contained in:
emersion 2018-10-02 12:11:09 +02:00
parent abd3e995ab
commit eac7c2ad2f
9 changed files with 47 additions and 23 deletions

View file

@ -1154,6 +1154,10 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
attempt_enable_needs_modeset(drm);
}
static int mhz_to_nsec(int mhz) {
return 1000000000000LL / mhz;
}
static void page_flip_handler(int fd, unsigned seq,
unsigned tv_sec, unsigned tv_usec, void *data) {
struct wlr_drm_connector *conn = data;
@ -1180,9 +1184,14 @@ static void page_flip_handler(int fd, unsigned seq,
.tv_sec = tv_sec,
.tv_nsec = tv_usec * 1000,
};
uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC |
WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION;
wlr_output_send_present(&conn->output, &present_time, seq, present_flags);
struct wlr_output_event_present present_event = {
.when = &present_time,
.seq = seq,
.refresh = mhz_to_nsec(conn->output.refresh),
.flags = WLR_OUTPUT_PRESENT_VSYNC | WLR_OUTPUT_PRESENT_HW_CLOCK |
WLR_OUTPUT_PRESENT_HW_COMPLETION,
};
wlr_output_send_present(&conn->output, &present_event);
if (drm->session->active) {
wlr_output_send_frame(&conn->output);

View file

@ -67,8 +67,9 @@ static bool output_make_current(struct wlr_output *wlr_output, int *buffer_age)
static bool output_swap_buffers(struct wlr_output *wlr_output,
pixman_region32_t *damage) {
wlr_output_send_present(wlr_output, NULL, 0, 0);
return true; // No-op
// Nothing needs to be done for pbuffers
wlr_output_send_present(wlr_output, NULL);
return true;
}
static void output_destroy(struct wlr_output *wlr_output) {

View file

@ -72,7 +72,7 @@ static bool output_swap_buffers(struct wlr_output *wlr_output,
}
// TODO: if available, use the presentation-time protocol
wlr_output_send_present(wlr_output, NULL, 0, 0);
wlr_output_send_present(wlr_output, NULL);
return true;
}

View file

@ -106,7 +106,7 @@ static bool output_swap_buffers(struct wlr_output *wlr_output,
return false;
}
wlr_output_send_present(wlr_output, NULL, 0, 0);
wlr_output_send_present(wlr_output, NULL);
return true;
}

View file

@ -45,7 +45,7 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled);
void wlr_output_update_needs_swap(struct wlr_output *output);
void wlr_output_damage_whole(struct wlr_output *output);
void wlr_output_send_frame(struct wlr_output *output);
void wlr_output_send_present(struct wlr_output *output, struct timespec *when,
unsigned seq, uint32_t flags);
void wlr_output_send_present(struct wlr_output *output,
struct wlr_output_event_present *event);
#endif

View file

@ -130,15 +130,28 @@ struct wlr_output_event_swap_buffers {
};
enum wlr_output_present_flag {
// The presentation was synchronized to the "vertical retrace" by the
// display hardware such that tearing does not happen.
WLR_OUTPUT_PRESENT_VSYNC = 0x1,
// The display hardware provided measurements that the hardware driver
// converted into a presentation timestamp.
WLR_OUTPUT_PRESENT_HW_CLOCK = 0x2,
// The display hardware signalled that it started using the new image
// content.
WLR_OUTPUT_PRESENT_HW_COMPLETION = 0x4,
// The presentation of this update was done zero-copy.
WLR_OUTPUT_PRESENT_ZERO_COPY = 0x8,
};
struct wlr_output_event_present {
struct wlr_output *output;
// Time when the content update turned into light the first time.
struct timespec *when;
// Vertical retrace counter. Zero if unavailable.
unsigned seq;
// Prediction of how many nanoseconds after `when` the very next output
// refresh may occur. Zero if unknown.
int refresh; // nsec
uint32_t flags; // enum wlr_output_present_flag
};

View file

@ -855,7 +855,7 @@ static void output_handle_present(struct wl_listener *listener, void *data) {
.output = output->wlr_output,
.tv_sec = (uint64_t)output_event->when->tv_sec,
.tv_nsec = (uint32_t)output_event->when->tv_nsec,
.refresh = 0, // TODO: predict next output vsync delay
.refresh = (uint32_t)output_event->refresh,
.seq = (uint64_t)output_event->seq,
.flags = output_event->flags,
};

View file

@ -561,10 +561,17 @@ void wlr_output_schedule_frame(struct wlr_output *output) {
wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output);
}
void wlr_output_send_present(struct wlr_output *output, struct timespec *when,
unsigned seq, uint32_t flags) {
void wlr_output_send_present(struct wlr_output *output,
struct wlr_output_event_present *event) {
struct wlr_output_event_present _event = {0};
if (event == NULL) {
event = &_event;
}
event->output = output;
struct timespec now;
if (when == NULL) {
if (event->when == NULL) {
clockid_t clock = wlr_backend_get_presentation_clock(output->backend);
errno = 0;
if (clock_gettime(clock, &now) != 0) {
@ -572,16 +579,10 @@ void wlr_output_send_present(struct wlr_output *output, struct timespec *when,
"failed to read clock");
return;
}
when = &now;
event->when = &now;
}
struct wlr_output_event_present event = {
.output = output,
.when = when,
.seq = seq,
.flags = flags,
};
wlr_signal_emit_safe(&output->events.present, &event);
wlr_signal_emit_safe(&output->events.present, event);
}
bool wlr_output_set_gamma(struct wlr_output *output, size_t size,

View file

@ -42,8 +42,8 @@ static void feedback_send_presented(struct wlr_presentation_feedback *feedback,
uint32_t seq_hi = event->seq >> 32;
uint32_t seq_lo = event->seq & 0xFFFFFFFF;
wp_presentation_feedback_send_presented(feedback->resource,
tv_sec_hi, tv_sec_lo, event->tv_nsec, event->refresh, seq_hi, seq_lo,
event->flags);
tv_sec_hi, tv_sec_lo, event->tv_nsec, event->refresh,
seq_hi, seq_lo, event->flags);
wl_resource_destroy(feedback->resource);
}