output: add presentation refresh prediction
This commit is contained in:
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…
Reference in New Issue