From ed59795572adb697176129770774eadb15a5b9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sun, 10 Sep 2023 03:35:33 +0200 Subject: [PATCH] vo: change vsync base to nanoseconds There is no reason to use microseconds precision. We have precise timers all all relevant platforms. --- player/video.c | 2 +- video/out/d3d11/context.c | 16 ++++++++-------- video/out/drm_common.c | 20 ++++++++++---------- video/out/drm_common.h | 2 +- video/out/present_sync.c | 30 +++++++++++++++--------------- video/out/present_sync.h | 10 +++++----- video/out/vo.c | 24 ++++++++++++------------ video/out/vo.h | 4 ++-- video/out/vo_vdpau.c | 2 +- video/out/wayland_common.c | 10 +++++----- video/out/x11_common.c | 2 +- 11 files changed, 61 insertions(+), 61 deletions(-) diff --git a/player/video.c b/player/video.c index 22e0dcf51b185..d2bb506d32028 100644 --- a/player/video.c +++ b/player/video.c @@ -835,7 +835,7 @@ static void handle_display_sync_frame(struct MPContext *mpctx, if (resample && using_spdif_passthrough(mpctx)) return; - double vsync = vo_get_vsync_interval(vo) / 1e6; + double vsync = vo_get_vsync_interval(vo) / 1e9; if (vsync <= 0) return; diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index a86b574fdd1d7..bc3171829e5e4 100644 --- a/video/out/d3d11/context.c +++ b/video/out/d3d11/context.c @@ -237,22 +237,22 @@ static bool d3d11_submit_frame(struct ra_swapchain *sw, return true; } -static int64_t qpc_to_us(struct ra_swapchain *sw, int64_t qpc) +static int64_t qpc_to_ns(struct ra_swapchain *sw, int64_t qpc) { struct priv *p = sw->priv; // Convert QPC units (1/perf_freq seconds) to microseconds. This will work // without overflow because the QPC value is guaranteed not to roll-over // within 100 years, so perf_freq must be less than 2.9*10^9. - return qpc / p->perf_freq * 1000000 + - qpc % p->perf_freq * 1000000 / p->perf_freq; + return qpc / p->perf_freq * UINT64_C(1000000000) + + qpc % p->perf_freq * UINT64_C(1000000000) / p->perf_freq; } -static int64_t qpc_us_now(struct ra_swapchain *sw) +static int64_t qpc_ns_now(struct ra_swapchain *sw) { LARGE_INTEGER perf_count; QueryPerformanceCounter(&perf_count); - return qpc_to_us(sw, perf_count.QuadPart); + return qpc_to_ns(sw, perf_count.QuadPart); } static void d3d11_swap_buffers(struct ra_swapchain *sw) @@ -330,7 +330,7 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info) if (src_passed && sqt_passed) p->vsync_duration_qpc = sqt_passed / src_passed; if (p->vsync_duration_qpc) - info->vsync_duration = qpc_to_us(sw, p->vsync_duration_qpc); + info->vsync_duration = qpc_to_ns(sw, p->vsync_duration_qpc); // If the physical frame rate is known and the other members of // DXGI_FRAME_STATISTICS are non-0, estimate the timing of the next frame @@ -353,8 +353,8 @@ static void d3d11_get_vsync(struct ra_swapchain *sw, struct vo_vsync_info *info) // Only set the estimated display time if it's after the last submission // time. It could be before if mpv skips a lot of frames. if (last_queue_display_time_qpc >= p->last_submit_qpc) { - info->last_queue_display_time = mp_time_us() + - (qpc_to_us(sw, last_queue_display_time_qpc) - qpc_us_now(sw)); + info->last_queue_display_time = mp_time_ns() + + (qpc_to_ns(sw, last_queue_display_time_qpc) - qpc_ns_now(sw)); } } } diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 0ec0788480944..ccca0367f9721 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -932,7 +932,7 @@ static void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec, struct drm_pflip_cb_closure *closure = data; struct drm_vsync_tuple *vsync = closure->vsync; - // frame_vsync->ust is the timestamp of the pageflip that happened just before this flip was queued + // frame_vsync->nst is the timestamp of the pageflip that happened just before this flip was queued // frame_vsync->msc is the sequence number of the pageflip that happened just before this flip was queued // frame_vsync->sbc is the sequence number for the frame that was just flipped to screen struct drm_vsync_tuple *frame_vsync = closure->frame_vsync; @@ -940,9 +940,9 @@ static void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec, const bool ready = (vsync->msc != 0) && - (frame_vsync->ust != 0) && (frame_vsync->msc != 0); + (frame_vsync->nst != 0) && (frame_vsync->msc != 0); - const uint64_t ust = (sec * 1000000LL) + usec; + const uint64_t nst = (sec * UINT64_C(1000000000)) + usec * UINT64_C(1000); const unsigned int msc_since_last_flip = msc - vsync->msc; if (ready && msc == vsync->msc) { @@ -955,7 +955,7 @@ static void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec, goto fail; } - vsync->ust = ust; + vsync->nst = nst; vsync->msc = msc; if (ready) { @@ -963,16 +963,16 @@ static void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec, struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) goto fail; - const uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - const uint64_t ust_mp_time = mp_time_us() - (now_monotonic - vsync->ust); + const uint64_t now_monotonic = ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec; + const uint64_t nst_mp_time = mp_time_ns() - (now_monotonic - vsync->nst); - const uint64_t ust_since_enqueue = vsync->ust - frame_vsync->ust; + const uint64_t nst_since_enqueue = vsync->nst - frame_vsync->nst; const unsigned int msc_since_enqueue = vsync->msc - frame_vsync->msc; const unsigned int sbc_since_enqueue = vsync->sbc - frame_vsync->sbc; - vsync_info->vsync_duration = ust_since_enqueue / msc_since_enqueue; + vsync_info->vsync_duration = nst_since_enqueue / msc_since_enqueue; vsync_info->skipped_vsyncs = msc_since_last_flip - 1; // Valid iff swap_buffers is called every vsync - vsync_info->last_queue_display_time = ust_mp_time + (sbc_since_enqueue * vsync_info->vsync_duration); + vsync_info->last_queue_display_time = nst_mp_time + (sbc_since_enqueue * vsync_info->vsync_duration); } fail: @@ -1004,7 +1004,7 @@ int vo_drm_control(struct vo *vo, int *events, int request, void *arg) drm->paused = false; drm->vsync_info.last_queue_display_time = -1; drm->vsync_info.skipped_vsyncs = 0; - drm->vsync.ust = 0; + drm->vsync.nst = 0; drm->vsync.msc = 0; return VO_TRUE; } diff --git a/video/out/drm_common.h b/video/out/drm_common.h index ac915848993aa..408e70caa519c 100644 --- a/video/out/drm_common.h +++ b/video/out/drm_common.h @@ -40,7 +40,7 @@ struct framebuffer { }; struct drm_vsync_tuple { - uint64_t ust; + uint64_t nst; unsigned int msc; unsigned int sbc; }; diff --git a/video/out/present_sync.c b/video/out/present_sync.c index 16d7416d43f83..c30b4b0c991e3 100644 --- a/video/out/present_sync.c +++ b/video/out/present_sync.c @@ -24,10 +24,10 @@ /* General nonsense about this mechanism. * * This requires that that caller has access to two, related values: - * (ust, msc): clock time and incrementing counter of last vsync (this is + * (nst, msc): clock time and incrementing counter of last vsync (this is * increased continuously, even if we don't swap) * - * Note that this concept originates from the GLX_OML_sync_control extension + * Note that this concept originates from the GLX_OML_sync_control extension * which includes another parameter: sbc (swap counter of frame that was * last displayed). Both the xorg present extension and wayland's * presentation-time protocol do not include sbc values so they are omitted @@ -44,12 +44,12 @@ void present_sync_get_info(struct mp_present *present, struct vo_vsync_info *inf void present_sync_swap(struct mp_present *present) { - int64_t ust = present->current_ust; + int64_t nst = present->current_nst; int64_t msc = present->current_msc; - // Avoid attempting to use any presentation statistics if the ust is 0 or has - // not actually updated (i.e. the last_ust is equal to current_ust). - if (!ust || ust == present->last_ust) { + // Avoid attempting to use any presentation statistics if the nst is 0 or has + // not actually updated (i.e. the last_nst is equal to current_nst). + if (!nst || nst == present->last_nst) { present->last_skipped_vsyncs = -1; present->vsync_duration = -1; present->last_queue_display_time = -1; @@ -58,28 +58,28 @@ void present_sync_swap(struct mp_present *present) present->last_skipped_vsyncs = 0; - int64_t ust_passed = ust ? ust - present->last_ust: 0; - present->last_ust = ust; + int64_t nst_passed = nst ? nst - present->last_nst: 0; + present->last_nst = nst; int64_t msc_passed = msc ? msc - present->last_msc: 0; present->last_msc = msc; - if (msc_passed && ust_passed) - present->vsync_duration = ust_passed / msc_passed; + if (msc_passed && nst_passed) + present->vsync_duration = nst_passed / msc_passed; struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) { return; } - uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; - uint64_t ust_mp_time = mp_time_us() - (now_monotonic - ust); + uint64_t now_monotonic = ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec; + uint64_t nst_mp_time = mp_time_us() - (now_monotonic - nst); - present->last_queue_display_time = ust_mp_time; + present->last_queue_display_time = nst_mp_time; } -void present_update_sync_values(struct mp_present *present, int64_t ust, +void present_update_sync_values(struct mp_present *present, int64_t nst, int64_t msc) { - present->current_ust = ust; + present->current_nst = nst; present->current_msc = msc; } diff --git a/video/out/present_sync.h b/video/out/present_sync.h index c310002b389ea..3e9c057cc763e 100644 --- a/video/out/present_sync.h +++ b/video/out/present_sync.h @@ -23,12 +23,12 @@ #include "vo.h" /* Generic helpers for obtaining presentation feedback from - * backend APIs. This requires ust/msc values. */ + * backend APIs. This requires nst/msc values. */ struct mp_present { - int64_t current_ust; + int64_t current_nst; int64_t current_msc; - int64_t last_ust; + int64_t last_nst; int64_t last_msc; int64_t vsync_duration; int64_t last_skipped_vsyncs; @@ -41,8 +41,8 @@ void present_sync_get_info(struct mp_present *present, struct vo_vsync_info *inf // Called after every buffer swap to update presentation statistics. void present_sync_swap(struct mp_present *present); -// Called anytime the backend delivers new ust/msc values. -void present_update_sync_values(struct mp_present *present, int64_t ust, +// Called anytime the backend delivers new nst/msc values. +void present_update_sync_values(struct mp_present *present, int64_t nst, int64_t msc); #endif /* MP_PRESENT_SYNC_H */ diff --git a/video/out/vo.c b/video/out/vo.c index faa172f2fd7cd..5a7546cbb7769 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -437,8 +437,8 @@ static void check_estimated_display_fps(struct vo *vo) bool use_estimated = false; if (in->num_total_vsync_samples >= MAX_VSYNC_SAMPLES / 2 && - in->estimated_vsync_interval <= 1e6 / 20.0 && - in->estimated_vsync_interval >= 1e6 / 99.0) + in->estimated_vsync_interval <= 1e9 / 20.0 && + in->estimated_vsync_interval >= 1e9 / 99.0) { for (int n = 0; n < in->num_vsync_samples; n++) { if (fabs(in->vsync_samples[n] - in->estimated_vsync_interval) @@ -451,13 +451,13 @@ static void check_estimated_display_fps(struct vo *vo) use_estimated = true; done: ; } - if (use_estimated == (in->vsync_interval == in->nominal_vsync_interval)) { + if (use_estimated == (fabs(in->vsync_interval - in->nominal_vsync_interval) < 1e9)) { if (use_estimated) { MP_VERBOSE(vo, "adjusting display FPS to a value closer to %.3f Hz\n", - 1e6 / in->estimated_vsync_interval); + 1e9 / in->estimated_vsync_interval); } else { MP_VERBOSE(vo, "switching back to assuming display fps = %.3f Hz\n", - 1e6 / in->nominal_vsync_interval); + 1e9 / in->nominal_vsync_interval); } } in->vsync_interval = use_estimated ? in->estimated_vsync_interval @@ -537,7 +537,7 @@ static void update_vsync_timing_after_swap(struct vo *vo, vsync_skip_detection(vo); MP_STATS(vo, "value %f jitter", in->estimated_vsync_jitter); - MP_STATS(vo, "value %f vsync-diff", in->vsync_samples[0] / 1e6); + MP_STATS(vo, "value %f vsync-diff", in->vsync_samples[0] / 1e9); } // to be called from VO thread only @@ -563,7 +563,7 @@ static void update_display_fps(struct vo *vo) display_fps = in->reported_display_fps; if (in->display_fps != display_fps) { - in->nominal_vsync_interval = display_fps > 0 ? 1e6 / display_fps : 0; + in->nominal_vsync_interval = display_fps > 0 ? 1e9 / display_fps : 0; in->vsync_interval = MPMAX(in->nominal_vsync_interval, 1); in->display_fps = display_fps; @@ -910,7 +910,7 @@ static bool render_frame(struct vo *vo) if (in->paused) frame->vsync_offset = 0; - int64_t now = mp_time_us(); + int64_t now = mp_time_ns(); int64_t pts = frame->pts; int64_t duration = frame->duration; int64_t end_time = pts + duration; @@ -926,7 +926,7 @@ static bool render_frame(struct vo *vo) in->dropped_frame &= frame->can_drop; // Even if we're hopelessly behind, rather degrade to 10 FPS playback, // instead of just freezing the display forever. - in->dropped_frame &= now - in->prev_vsync < 100 * 1000; + in->dropped_frame &= now - in->prev_vsync < 100 * 1000000; in->dropped_frame &= in->hasframe_rendered; // Setup parameters for the next time this frame is drawn. ("frame" is the @@ -991,7 +991,7 @@ static bool render_frame(struct vo *vo) // Make up some crap if presentation feedback is missing. if (vsync.last_queue_display_time < 0) - vsync.last_queue_display_time = mp_time_us(); + vsync.last_queue_display_time = mp_time_ns(); stats_time_end(in->stats, "video-flip"); @@ -1303,7 +1303,7 @@ double vo_get_estimated_vsync_interval(struct vo *vo) { struct vo_internal *in = vo->in; pthread_mutex_lock(&in->lock); - double res = in->estimated_vsync_interval / 1e6; + double res = in->estimated_vsync_interval / 1e9; pthread_mutex_unlock(&in->lock); return res; } @@ -1337,7 +1337,7 @@ double vo_get_delay(struct vo *vo) res = 0; } pthread_mutex_unlock(&in->lock); - return res ? (res - mp_time_us()) / 1e6 : 0; + return res ? (res - mp_time_ns()) / 1e9 : 0; } void vo_discard_timing_info(struct vo *vo) diff --git a/video/out/vo.h b/video/out/vo.h index 518181efb0242..c2d2044bce962 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -268,13 +268,13 @@ struct vo_frame { // Presentation feedback. See get_vsync() for how backends should fill this // struct. struct vo_vsync_info { - // mp_time_us() timestamp at which the last queued frame will likely be + // mp_time_ns() timestamp at which the last queued frame will likely be // displayed (this is in the future, unless the frame is instantly output). // -1 if unset or unsupported. // This implies the latency of the output. int64_t last_queue_display_time; - // Time between 2 vsync events in microseconds. The difference should be the + // Time between 2 vsync events in nanoseconds. The difference should be the // from 2 times sampled from the same reference point (it should not be the // difference between e.g. the end of scanout and the start of the next one; // it must be continuous). diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 1ccfe1d84f885..fcb135bbf25aa 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -766,7 +766,7 @@ static void flip_page(struct vo *vo) if (vc->user_fps > 0) { vc->vsync_interval = 1e9 / vc->user_fps; } else if (vc->user_fps == 0) { - vc->vsync_interval = vo_get_vsync_interval(vo) * 1000; + vc->vsync_interval = vo_get_vsync_interval(vo); } vc->vsync_interval = MPMAX(vc->vsync_interval, 1); diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 8179436c2124f..5b2942191c39a 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -1156,9 +1156,9 @@ static void feedback_presented(void *data, struct wp_presentation_feedback *fbac // - these values are updated every time the compositor receives feedback. int64_t sec = (uint64_t) tv_sec_lo + ((uint64_t) tv_sec_hi << 32); - int64_t ust = sec * 1000000LL + (uint64_t) tv_nsec / 1000; + int64_t nst = sec * UINT64_C(1000000000) + (uint64_t) tv_nsec; int64_t msc = (uint64_t) seq_lo + ((uint64_t) seq_hi << 32); - present_update_sync_values(wl->present, ust, msc); + present_update_sync_values(wl->present, nst, msc); } static void feedback_discarded(void *data, struct wp_presentation_feedback *fback) @@ -2581,10 +2581,10 @@ void vo_wayland_wait_frame(struct vo_wayland_state *wl) // Completely arbitrary amount of additional time to wait. vblank_time += 0.05 * vblank_time; - int64_t finish_time = mp_time_us() + vblank_time; + int64_t finish_time = mp_time_ns() + vblank_time; - while (wl->frame_wait && finish_time > mp_time_us()) { - int poll_time = ceil((double)(finish_time - mp_time_us()) / 1000); + while (wl->frame_wait && finish_time > mp_time_ns()) { + int poll_time = ceil((double)(finish_time - mp_time_ns()) / 1000000); if (poll_time < 0) { poll_time = 0; } diff --git a/video/out/x11_common.c b/video/out/x11_common.c index 3c0f275370e62..8ba8cda7bd72d 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -1327,7 +1327,7 @@ void vo_x11_check_events(struct vo *vo) if (cookie->evtype == PresentCompleteNotify) { XPresentCompleteNotifyEvent *present_event; present_event = (XPresentCompleteNotifyEvent *)cookie->data; - present_update_sync_values(x11->present, present_event->ust, + present_update_sync_values(x11->present, present_event->nst, present_event->msc); } }