From 78389fe72225f9baf7def744825323f54ac4ee8e Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 29 Sep 2018 22:38:13 +0200 Subject: output: add present event --- backend/drm/drm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'backend/drm') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index fa9a95ae..ace0835e 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1149,8 +1149,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } static void page_flip_handler(int fd, unsigned seq, - unsigned tv_sec, unsigned tv_usec, void *user) { - struct wlr_drm_connector *conn = user; + unsigned tv_sec, unsigned tv_usec, void *data) { + struct wlr_drm_connector *conn = data; struct wlr_drm_backend *drm = get_drm_backend_from_backend(conn->output.backend); @@ -1170,6 +1170,14 @@ static void page_flip_handler(int fd, unsigned seq, post_drm_surface(&conn->crtc->primary->mgpu_surf); } + struct timespec present_time = { + .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); + if (drm->session->active) { wlr_output_send_frame(&conn->output); } -- cgit v1.2.3 From 54e1287f307d13566deaf51683da373f3524d1d9 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 1 Oct 2018 22:44:33 +0200 Subject: backend: add get_present_clock --- backend/backend.c | 7 +++++++ backend/drm/backend.c | 6 ++++++ backend/drm/drm.c | 12 +++++++++--- include/backend/drm/drm.h | 2 ++ include/wlr/backend.h | 4 ++++ include/wlr/backend/interface.h | 2 ++ types/wlr_output.c | 6 +++--- 7 files changed, 33 insertions(+), 6 deletions(-) (limited to 'backend/drm') diff --git a/backend/backend.c b/backend/backend.c index 2d6464b7..b8cf8797 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -64,6 +64,13 @@ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) { return NULL; } +clockid_t wlr_backend_get_present_clock(struct wlr_backend *backend) { + if (backend->impl->get_present_clock) { + return backend->impl->get_present_clock(backend); + } + return CLOCK_MONOTONIC; +} + static size_t parse_outputs_env(const char *name) { const char *outputs_str = getenv(name); if (outputs_str == NULL) { diff --git a/backend/drm/backend.c b/backend/drm/backend.c index b298365e..b230613d 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -65,10 +65,16 @@ static struct wlr_renderer *backend_get_renderer( } } +static clockid_t backend_get_present_clock(struct wlr_backend *backend) { + struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); + return drm->clock; +} + static struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, .get_renderer = backend_get_renderer, + .get_present_clock = backend_get_present_clock, }; bool wlr_backend_is_drm(struct wlr_backend *b) { diff --git a/backend/drm/drm.c b/backend/drm/drm.c index ace0835e..753b6ab8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 199309L #include #include #include @@ -27,8 +28,8 @@ #include "util/signal.h" bool check_drm_features(struct wlr_drm_backend *drm) { + uint64_t cap; if (drm->parent) { - uint64_t cap; if (drmGetCap(drm->fd, DRM_CAP_PRIME, &cap) || !(cap & DRM_PRIME_CAP_IMPORT)) { wlr_log(WLR_ERROR, @@ -51,16 +52,21 @@ bool check_drm_features(struct wlr_drm_backend *drm) { const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC"); if (no_atomic && strcmp(no_atomic, "1") == 0) { - wlr_log(WLR_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); + wlr_log(WLR_DEBUG, + "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); drm->iface = &legacy_iface; } else if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { - wlr_log(WLR_DEBUG, "Atomic modesetting unsupported, using legacy DRM interface"); + wlr_log(WLR_DEBUG, + "Atomic modesetting unsupported, using legacy DRM interface"); drm->iface = &legacy_iface; } else { wlr_log(WLR_DEBUG, "Using atomic DRM interface"); drm->iface = &atomic_iface; } + int ret = drmGetCap(drm->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap); + drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME; + return true; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 3c728808..de5212d3 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct wlr_drm_backend { struct wlr_drm_backend *parent; const struct wlr_drm_interface *iface; + clockid_t clock; int fd; diff --git a/include/wlr/backend.h b/include/wlr/backend.h index dfb8d2a8..aee45b73 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -62,5 +62,9 @@ struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend); * Might return NULL for backends that don't use a session. */ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend); +/** + * Returns the clock used by the backend for presentation feedback. + */ +clockid_t wlr_backend_get_present_clock(struct wlr_backend *backend); #endif diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index 2c300709..a930c241 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -10,6 +10,7 @@ #define WLR_BACKEND_INTERFACE_H #include +#include #include #include @@ -18,6 +19,7 @@ struct wlr_backend_impl { void (*destroy)(struct wlr_backend *backend); struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend); struct wlr_session *(*get_session)(struct wlr_backend *backend); + clockid_t (*get_present_clock)(struct wlr_backend *backend); }; /** diff --git a/types/wlr_output.c b/types/wlr_output.c index 4ffe561a..1baa5027 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -18,8 +18,6 @@ #define OUTPUT_VERSION 3 -#define DEFAULT_PRESENT_CLOCK CLOCK_MONOTONIC - static void output_send_to_resource(struct wl_resource *resource) { struct wlr_output *output = wlr_output_from_resource(resource); const uint32_t version = wl_resource_get_version(resource); @@ -268,6 +266,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, wl_signal_init(&output->events.frame); wl_signal_init(&output->events.needs_swap); wl_signal_init(&output->events.swap_buffers); + wl_signal_init(&output->events.present); wl_signal_init(&output->events.enable); wl_signal_init(&output->events.mode); wl_signal_init(&output->events.scale); @@ -566,7 +565,8 @@ void wlr_output_send_present(struct wlr_output *output, struct timespec *when, unsigned seq, uint32_t flags) { struct timespec now; if (when == NULL) { - if (!clock_gettime(DEFAULT_PRESENT_CLOCK, &now)) { + clockid_t clock = wlr_backend_get_present_clock(output->backend); + if (!clock_gettime(clock, &now)) { wlr_log_errno(WLR_ERROR, "failed to send output present event: " "failed to read clock"); return; -- cgit v1.2.3 From b0635bf3e7f0de7c641ffafb0e8962d62ee88c73 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 1 Oct 2018 22:57:36 +0200 Subject: Rename get_present_clock to get_presentation clock, use it --- backend/backend.c | 6 +++--- backend/drm/backend.c | 4 ++-- backend/multi/backend.c | 17 +++++++++++++++++ include/wlr/backend.h | 2 +- include/wlr/backend/interface.h | 2 +- include/wlr/types/wlr_presentation_time.h | 5 ++++- types/wlr_output.c | 2 +- types/wlr_presentation_time.c | 9 +++++---- 8 files changed, 34 insertions(+), 13 deletions(-) (limited to 'backend/drm') diff --git a/backend/backend.c b/backend/backend.c index b8cf8797..4b186767 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -64,9 +64,9 @@ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend) { return NULL; } -clockid_t wlr_backend_get_present_clock(struct wlr_backend *backend) { - if (backend->impl->get_present_clock) { - return backend->impl->get_present_clock(backend); +clockid_t wlr_backend_get_presentation_clock(struct wlr_backend *backend) { + if (backend->impl->get_presentation_clock) { + return backend->impl->get_presentation_clock(backend); } return CLOCK_MONOTONIC; } diff --git a/backend/drm/backend.c b/backend/drm/backend.c index b230613d..a9082077 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -65,7 +65,7 @@ static struct wlr_renderer *backend_get_renderer( } } -static clockid_t backend_get_present_clock(struct wlr_backend *backend) { +static clockid_t backend_get_presentation_clock(struct wlr_backend *backend) { struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend); return drm->clock; } @@ -74,7 +74,7 @@ static struct wlr_backend_impl backend_impl = { .start = backend_start, .destroy = backend_destroy, .get_renderer = backend_get_renderer, - .get_present_clock = backend_get_present_clock, + .get_presentation_clock = backend_get_presentation_clock, }; bool wlr_backend_is_drm(struct wlr_backend *b) { diff --git a/backend/multi/backend.c b/backend/multi/backend.c index 2f4b929f..cefaa361 100644 --- a/backend/multi/backend.c +++ b/backend/multi/backend.c @@ -1,6 +1,8 @@ +#define _POSIX_C_SOURCE 199309L #include #include #include +#include #include #include #include @@ -77,11 +79,26 @@ static struct wlr_session *multi_backend_get_session( return backend->session; } +static clockid_t multi_backend_get_presentation_clock( + struct wlr_backend *backend) { + struct wlr_multi_backend *multi = multi_backend_from_backend(backend); + + struct subbackend_state *sub; + wl_list_for_each(sub, &multi->backends, link) { + if (sub->backend->impl->get_presentation_clock) { + return wlr_backend_get_presentation_clock(sub->backend); + } + } + + return CLOCK_MONOTONIC; +} + struct wlr_backend_impl backend_impl = { .start = multi_backend_start, .destroy = multi_backend_destroy, .get_renderer = multi_backend_get_renderer, .get_session = multi_backend_get_session, + .get_presentation_clock = multi_backend_get_presentation_clock, }; static void handle_display_destroy(struct wl_listener *listener, void *data) { diff --git a/include/wlr/backend.h b/include/wlr/backend.h index aee45b73..54f2b5e8 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -65,6 +65,6 @@ struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend); /** * Returns the clock used by the backend for presentation feedback. */ -clockid_t wlr_backend_get_present_clock(struct wlr_backend *backend); +clockid_t wlr_backend_get_presentation_clock(struct wlr_backend *backend); #endif diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index a930c241..4a6a5cbb 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -19,7 +19,7 @@ struct wlr_backend_impl { void (*destroy)(struct wlr_backend *backend); struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend); struct wlr_session *(*get_session)(struct wlr_backend *backend); - clockid_t (*get_present_clock)(struct wlr_backend *backend); + clockid_t (*get_presentation_clock)(struct wlr_backend *backend); }; /** diff --git a/include/wlr/types/wlr_presentation_time.h b/include/wlr/types/wlr_presentation_time.h index 71bf5977..9f9f0e87 100644 --- a/include/wlr/types/wlr_presentation_time.h +++ b/include/wlr/types/wlr_presentation_time.h @@ -47,7 +47,10 @@ struct wlr_presentation_event { uint32_t flags; // wp_presentation_feedback_kind }; -struct wlr_presentation *wlr_presentation_create(struct wl_display *display); +struct wlr_backend; + +struct wlr_presentation *wlr_presentation_create(struct wl_display *display, + struct wlr_backend *backend); void wlr_presentation_destroy(struct wlr_presentation *presentation); void wlr_presentation_send_surface_presented( struct wlr_presentation *presentation, struct wlr_surface *surface, diff --git a/types/wlr_output.c b/types/wlr_output.c index 6ff06fd6..25cd0734 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -565,7 +565,7 @@ void wlr_output_send_present(struct wlr_output *output, struct timespec *when, unsigned seq, uint32_t flags) { struct timespec now; if (when == NULL) { - clockid_t clock = wlr_backend_get_present_clock(output->backend); + clockid_t clock = wlr_backend_get_presentation_clock(output->backend); errno = 0; if (clock_gettime(clock, &now) != 0) { wlr_log_errno(WLR_ERROR, "failed to send output present event: " diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index 710aa4b9..c83b5e99 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "presentation-time-protocol.h" #include "util/signal.h" @@ -147,7 +148,7 @@ static void presentation_bind(struct wl_client *client, void *data, presentation_handle_resource_destroy); wl_list_insert(&presentation->resources, wl_resource_get_link(resource)); - wp_presentation_send_clock_id(resource, presentation->clock); + wp_presentation_send_clock_id(resource, (uint32_t)presentation->clock); } static void handle_display_destroy(struct wl_listener *listener, void *data) { @@ -156,7 +157,8 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_presentation_destroy(presentation); } -struct wlr_presentation *wlr_presentation_create(struct wl_display *display) { +struct wlr_presentation *wlr_presentation_create(struct wl_display *display, + struct wlr_backend *backend) { struct wlr_presentation *presentation = calloc(1, sizeof(struct wlr_presentation)); if (presentation == NULL) { @@ -170,8 +172,7 @@ struct wlr_presentation *wlr_presentation_create(struct wl_display *display) { return NULL; } - // TODO: get clock from backend - presentation->clock = CLOCK_MONOTONIC; + presentation->clock = wlr_backend_get_presentation_clock(backend); wl_list_init(&presentation->resources); wl_list_init(&presentation->feedbacks); -- cgit v1.2.3 From eac7c2ad2faf49084342d9f805cf06b773723fdd Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 2 Oct 2018 12:11:09 +0200 Subject: output: add presentation refresh prediction --- backend/drm/drm.c | 15 ++++++++++++--- backend/headless/output.c | 5 +++-- backend/wayland/output.c | 2 +- backend/x11/output.c | 2 +- include/wlr/interfaces/wlr_output.h | 4 ++-- include/wlr/types/wlr_output.h | 13 +++++++++++++ rootston/output.c | 2 +- types/wlr_output.c | 23 ++++++++++++----------- types/wlr_presentation_time.c | 4 ++-- 9 files changed, 47 insertions(+), 23 deletions(-) (limited to 'backend/drm') diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 753b6ab8..0187e5d0 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -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); diff --git a/backend/headless/output.c b/backend/headless/output.c index ad0050d8..3cb35dce 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -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) { diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 4fbfe9d2..bc7a9f05 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -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; } diff --git a/backend/x11/output.c b/backend/x11/output.c index 8cd8ee33..1ac12a8d 100644 --- a/backend/x11/output.c +++ b/backend/x11/output.c @@ -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; } diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index b06c5db0..52581768 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -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 diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index fb3becd1..9ccfbbb5 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -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 }; diff --git a/rootston/output.c b/rootston/output.c index 8168a0c3..9d376f8e 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -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, }; diff --git a/types/wlr_output.c b/types/wlr_output.c index 25cd0734..b3840415 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -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, diff --git a/types/wlr_presentation_time.c b/types/wlr_presentation_time.c index c83b5e99..eeba47b6 100644 --- a/types/wlr_presentation_time.c +++ b/types/wlr_presentation_time.c @@ -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); } -- cgit v1.2.3