mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
vo: use a struct for vsync feedback stuff
So new useless stuff can be easily added.
This commit is contained in:
@@ -84,14 +84,8 @@ struct ra_swapchain_fns {
|
||||
// params.swapchain_depth, or until the next vblank (for vsynced contexts)
|
||||
void (*swap_buffers)(struct ra_swapchain *sw);
|
||||
|
||||
// Return the latency at which swap_buffers() is performed. This is in
|
||||
// seconds and always >= 0. Essentially, it's the predicted time the last
|
||||
// shown frame will take until it is actually displayed on the physical
|
||||
// screen. (A reasonable implementation is returning the duration the
|
||||
// last actually displayed frame took after its swap_buffers() was called.)
|
||||
// Should return -1 on error (e.g. discontinuities).
|
||||
// Can be NULL 0 or always return -1 if unsupported.
|
||||
double (*get_latency)(struct ra_swapchain *sw);
|
||||
// See vo. Usually called after swap_buffers().
|
||||
void (*get_vsync)(struct ra_swapchain *sw, struct vo_vsync_info *info);
|
||||
};
|
||||
|
||||
// Create and destroy a ra_ctx. This also takes care of creating and destroying
|
||||
|
||||
@@ -313,10 +313,12 @@ void ra_gl_ctx_swap_buffers(struct ra_swapchain *sw)
|
||||
}
|
||||
}
|
||||
|
||||
static double ra_gl_ctx_get_latency(struct ra_swapchain *sw)
|
||||
static void ra_gl_ctx_get_vsync(struct ra_swapchain *sw,
|
||||
struct vo_vsync_info *info)
|
||||
{
|
||||
struct priv *p = sw->priv;
|
||||
return p->params.get_latency ? p->params.get_latency(sw->ctx) : -1;
|
||||
if (p->params.get_vsync)
|
||||
p->params.get_vsync(sw->ctx, info);
|
||||
}
|
||||
|
||||
static const struct ra_swapchain_fns ra_gl_swapchain_fns = {
|
||||
@@ -324,5 +326,5 @@ static const struct ra_swapchain_fns ra_gl_swapchain_fns = {
|
||||
.start_frame = ra_gl_ctx_start_frame,
|
||||
.submit_frame = ra_gl_ctx_submit_frame,
|
||||
.swap_buffers = ra_gl_ctx_swap_buffers,
|
||||
.get_latency = ra_gl_ctx_get_latency,
|
||||
.get_vsync = ra_gl_ctx_get_vsync,
|
||||
};
|
||||
|
||||
@@ -23,8 +23,8 @@ struct ra_gl_ctx_params {
|
||||
// function or if you override it yourself.
|
||||
void (*swap_buffers)(struct ra_ctx *ctx);
|
||||
|
||||
// See ra_swapchain_fns.get_latency.
|
||||
double (*get_latency)(struct ra_ctx *ctx);
|
||||
// See ra_swapchain_fns.get_vsync.
|
||||
void (*get_vsync)(struct ra_ctx *ctx, struct vo_vsync_info *info);
|
||||
|
||||
// Set to false if the implementation follows normal GL semantics, which is
|
||||
// upside down. Set to true if it does *not*, i.e. if rendering is right
|
||||
|
||||
@@ -305,10 +305,10 @@ static void glx_swap_buffers(struct ra_ctx *ctx)
|
||||
p->latency = update_latency_oml(ctx);
|
||||
}
|
||||
|
||||
static double glx_get_latency(struct ra_ctx *ctx)
|
||||
static void glx_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
return p->latency;
|
||||
info->latency = p->latency;
|
||||
}
|
||||
|
||||
static bool glx_init(struct ra_ctx *ctx)
|
||||
@@ -394,7 +394,7 @@ static bool glx_init(struct ra_ctx *ctx)
|
||||
|
||||
struct ra_gl_ctx_params params = {
|
||||
.swap_buffers = glx_swap_buffers,
|
||||
.get_latency = glx_get_latency,
|
||||
.get_vsync = glx_get_vsync,
|
||||
};
|
||||
|
||||
if (!ra_gl_ctx_init(ctx, gl, params))
|
||||
|
||||
@@ -141,7 +141,6 @@ struct vo_internal {
|
||||
double estimated_vsync_jitter;
|
||||
bool expecting_vsync;
|
||||
int64_t num_successive_vsyncs;
|
||||
double last_vo_latency;
|
||||
|
||||
int64_t flip_queue_offset; // queue flip events at most this much in advance
|
||||
int64_t timing_offset; // same (but from options; not VO configured)
|
||||
@@ -475,18 +474,14 @@ static void vsync_skip_detection(struct vo *vo)
|
||||
}
|
||||
|
||||
// Always called locked.
|
||||
static void update_vsync_timing_after_swap(struct vo *vo)
|
||||
static void update_vsync_timing_after_swap(struct vo *vo,
|
||||
struct vo_vsync_info *vsync)
|
||||
{
|
||||
struct vo_internal *in = vo->in;
|
||||
|
||||
int64_t now = mp_time_us();
|
||||
int64_t vsync_time = vsync->last_queue_time;
|
||||
int64_t prev_vsync = in->prev_vsync;
|
||||
|
||||
// If we can, use a "made up" expected display time.
|
||||
if (in->last_vo_latency >= 0)
|
||||
now += in->last_vo_latency * (1000.0 * 1000.0);
|
||||
|
||||
in->prev_vsync = now;
|
||||
in->prev_vsync = vsync_time;
|
||||
|
||||
if (!in->expecting_vsync) {
|
||||
reset_vsync_timings(vo);
|
||||
@@ -500,13 +495,13 @@ static void update_vsync_timing_after_swap(struct vo *vo)
|
||||
if (in->num_vsync_samples >= MAX_VSYNC_SAMPLES)
|
||||
in->num_vsync_samples -= 1;
|
||||
MP_TARRAY_INSERT_AT(in, in->vsync_samples, in->num_vsync_samples, 0,
|
||||
now - prev_vsync);
|
||||
vsync_time - prev_vsync);
|
||||
in->drop_point = MPMIN(in->drop_point + 1, in->num_vsync_samples);
|
||||
in->num_total_vsync_samples += 1;
|
||||
if (in->base_vsync) {
|
||||
in->base_vsync += in->vsync_interval;
|
||||
} else {
|
||||
in->base_vsync = now;
|
||||
in->base_vsync = vsync_time;
|
||||
}
|
||||
|
||||
double avg = 0;
|
||||
@@ -915,17 +910,24 @@ bool vo_render_frame_external(struct vo *vo)
|
||||
|
||||
vo->driver->flip_page(vo);
|
||||
|
||||
double latency =
|
||||
vo->driver->get_latency ? vo->driver->get_latency(vo) : -1;
|
||||
struct vo_vsync_info vsync = {
|
||||
.last_queue_time = mp_time_us(),
|
||||
.latency = -1,
|
||||
};
|
||||
if (vo->driver->get_vsync)
|
||||
vo->driver->get_vsync(vo, &vsync);
|
||||
|
||||
// If we can, use a "made up" expected display time.
|
||||
if (vsync.latency >= 0)
|
||||
vsync.last_queue_time += vsync.latency * (1000.0 * 1000.0);
|
||||
|
||||
MP_STATS(vo, "end video-flip");
|
||||
|
||||
pthread_mutex_lock(&in->lock);
|
||||
in->dropped_frame = prev_drop_count < vo->in->drop_count;
|
||||
in->rendering = false;
|
||||
in->last_vo_latency = latency;
|
||||
|
||||
update_vsync_timing_after_swap(vo);
|
||||
update_vsync_timing_after_swap(vo, &vsync);
|
||||
}
|
||||
|
||||
if (vo->driver->caps & VO_CAP_NORETAIN) {
|
||||
|
||||
@@ -263,6 +263,21 @@ struct vo_frame {
|
||||
uint64_t frame_id;
|
||||
};
|
||||
|
||||
// Presentation feedback.
|
||||
struct vo_vsync_info {
|
||||
// Last mp_time_us() timestamp at which a frame was queued.
|
||||
int64_t last_queue_time;
|
||||
|
||||
// The latency at which swap_buffers() is performed. This is in seconds, and
|
||||
// valid values are always >= 0. Essentially, it's the predicted time the
|
||||
// last shown frame will take until it is actually displayed on the physical
|
||||
// screen. (A reasonable implementation is returning the actual measured
|
||||
// value for the last frame which was actually displayed. The assumption is
|
||||
// that the latency usually doesn't change.)
|
||||
// -1 if unset or unsupported.
|
||||
double latency;
|
||||
};
|
||||
|
||||
struct vo_driver {
|
||||
// Encoding functionality, which can be invoked via --o only.
|
||||
bool encode;
|
||||
@@ -375,9 +390,11 @@ struct vo_driver {
|
||||
void (*flip_page)(struct vo *vo);
|
||||
|
||||
/*
|
||||
* See struct ra_swapchain. Optional.
|
||||
* Return presentation feedback. The implementation should not touch fields
|
||||
* it doesn't support; the info fields are preinitialized to neutral values.
|
||||
* Usually called once after flip_page(), but can be called any time.
|
||||
*/
|
||||
double (*get_latency)(struct vo *vo);
|
||||
void (*get_vsync)(struct vo *vo, struct vo_vsync_info *info);
|
||||
|
||||
/* These optional callbacks can be provided if the GUI framework used by
|
||||
* the VO requires entering a message loop for receiving events and does
|
||||
|
||||
@@ -98,11 +98,12 @@ static void flip_page(struct vo *vo)
|
||||
sw->fns->swap_buffers(sw);
|
||||
}
|
||||
|
||||
static double get_latency(struct vo *vo)
|
||||
static void get_vsync(struct vo *vo, struct vo_vsync_info *info)
|
||||
{
|
||||
struct gpu_priv *p = vo->priv;
|
||||
struct ra_swapchain *sw = p->ctx->swapchain;
|
||||
return sw->fns->get_latency ? sw->fns->get_latency(sw) : -1;
|
||||
if (sw->fns->get_vsync)
|
||||
sw->fns->get_vsync(sw, info);
|
||||
}
|
||||
|
||||
static int query_format(struct vo *vo, int format)
|
||||
@@ -333,7 +334,7 @@ const struct vo_driver video_out_gpu = {
|
||||
.get_image = get_image,
|
||||
.draw_frame = draw_frame,
|
||||
.flip_page = flip_page,
|
||||
.get_latency = get_latency,
|
||||
.get_vsync = get_vsync,
|
||||
.wait_events = wait_events,
|
||||
.wakeup = wakeup,
|
||||
.uninit = uninit,
|
||||
|
||||
Reference in New Issue
Block a user