Skip to content

Commit

Permalink
vo: change vsync base to nanoseconds
Browse files Browse the repository at this point in the history
There is no reason to use microseconds precision. We have precise timers
all all relevant platforms.
  • Loading branch information
kasper93 committed Sep 10, 2023
1 parent 5135f3b commit ab222d2
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 59 deletions.
2 changes: 1 addition & 1 deletion player/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
16 changes: 8 additions & 8 deletions video/out/d3d11/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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));
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions video/out/drm_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -955,24 +955,24 @@ 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) {
// Convert to mp_time
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:
Expand Down
2 changes: 1 addition & 1 deletion video/out/drm_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct framebuffer {
};

struct drm_vsync_tuple {
uint64_t ust;
uint64_t nst;
unsigned int msc;
unsigned int sbc;
};
Expand Down
30 changes: 15 additions & 15 deletions video/out/present_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
}
10 changes: 5 additions & 5 deletions video/out/present_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
24 changes: 12 additions & 12 deletions video/out/vo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions video/out/vo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 1 addition & 1 deletion video/out/vo_vdpau.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
10 changes: 5 additions & 5 deletions video/out/wayland_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion video/out/x11_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down

0 comments on commit ab222d2

Please sign in to comment.