output: add presentation refresh prediction

master
emersion 6 years ago
parent abd3e995ab
commit eac7c2ad2f

@ -1154,6 +1154,10 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
attempt_enable_needs_modeset(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, static void page_flip_handler(int fd, unsigned seq,
unsigned tv_sec, unsigned tv_usec, void *data) { unsigned tv_sec, unsigned tv_usec, void *data) {
struct wlr_drm_connector *conn = 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_sec = tv_sec,
.tv_nsec = tv_usec * 1000, .tv_nsec = tv_usec * 1000,
}; };
uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC | struct wlr_output_event_present present_event = {
WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION; .when = &present_time,
wlr_output_send_present(&conn->output, &present_time, seq, present_flags); .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) { if (drm->session->active) {
wlr_output_send_frame(&conn->output); wlr_output_send_frame(&conn->output);

@ -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, static bool output_swap_buffers(struct wlr_output *wlr_output,
pixman_region32_t *damage) { pixman_region32_t *damage) {
wlr_output_send_present(wlr_output, NULL, 0, 0); // Nothing needs to be done for pbuffers
return true; // No-op wlr_output_send_present(wlr_output, NULL);
return true;
} }
static void output_destroy(struct wlr_output *wlr_output) { static void output_destroy(struct wlr_output *wlr_output) {

@ -72,7 +72,7 @@ static bool output_swap_buffers(struct wlr_output *wlr_output,
} }
// TODO: if available, use the presentation-time protocol // 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; return true;
} }

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

@ -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_update_needs_swap(struct wlr_output *output);
void wlr_output_damage_whole(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_frame(struct wlr_output *output);
void wlr_output_send_present(struct wlr_output *output, struct timespec *when, void wlr_output_send_present(struct wlr_output *output,
unsigned seq, uint32_t flags); struct wlr_output_event_present *event);
#endif #endif

@ -130,15 +130,28 @@ struct wlr_output_event_swap_buffers {
}; };
enum wlr_output_present_flag { 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, 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, WLR_OUTPUT_PRESENT_HW_CLOCK = 0x2,
// The display hardware signalled that it started using the new image
// content.
WLR_OUTPUT_PRESENT_HW_COMPLETION = 0x4, 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_event_present {
struct wlr_output *output; struct wlr_output *output;
// Time when the content update turned into light the first time.
struct timespec *when; struct timespec *when;
// Vertical retrace counter. Zero if unavailable.
unsigned seq; 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 uint32_t flags; // enum wlr_output_present_flag
}; };

@ -855,7 +855,7 @@ static void output_handle_present(struct wl_listener *listener, void *data) {
.output = output->wlr_output, .output = output->wlr_output,
.tv_sec = (uint64_t)output_event->when->tv_sec, .tv_sec = (uint64_t)output_event->when->tv_sec,
.tv_nsec = (uint32_t)output_event->when->tv_nsec, .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, .seq = (uint64_t)output_event->seq,
.flags = output_event->flags, .flags = output_event->flags,
}; };

@ -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); wl_event_loop_add_idle(ev, schedule_frame_handle_idle_timer, output);
} }
void wlr_output_send_present(struct wlr_output *output, struct timespec *when, void wlr_output_send_present(struct wlr_output *output,
unsigned seq, uint32_t flags) { struct wlr_output_event_present *event) {
struct wlr_output_event_present _event = {0};
if (event == NULL) {
event = &_event;
}
event->output = output;
struct timespec now; struct timespec now;
if (when == NULL) { if (event->when == NULL) {
clockid_t clock = wlr_backend_get_presentation_clock(output->backend); clockid_t clock = wlr_backend_get_presentation_clock(output->backend);
errno = 0; errno = 0;
if (clock_gettime(clock, &now) != 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"); "failed to read clock");
return; return;
} }
when = &now; event->when = &now;
} }
struct wlr_output_event_present event = { wlr_signal_emit_safe(&output->events.present, event);
.output = output,
.when = when,
.seq = seq,
.flags = flags,
};
wlr_signal_emit_safe(&output->events.present, &event);
} }
bool wlr_output_set_gamma(struct wlr_output *output, size_t size, bool wlr_output_set_gamma(struct wlr_output *output, size_t size,

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

Loading…
Cancel
Save