vo: use a struct for vsync feedback stuff

So new useless stuff can be easily added.
This commit is contained in:
wm4
2018-08-31 20:08:08 +02:00
committed by Anton Kindestam
parent 83884fdf03
commit b1ba7de34d
7 changed files with 52 additions and 36 deletions

View File

@@ -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

View File

@@ -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,
};

View File

@@ -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

View File

@@ -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))

View File

@@ -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) {

View File

@@ -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

View File

@@ -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,