From b1ba7de34dd5685a082454817f23509d1c28e4aa Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 31 Aug 2018 20:08:08 +0200 Subject: vo: use a struct for vsync feedback stuff So new useless stuff can be easily added. --- video/out/gpu/context.h | 10 ++-------- video/out/opengl/context.c | 8 +++++--- video/out/opengl/context.h | 4 ++-- video/out/opengl/context_glx.c | 6 +++--- video/out/vo.c | 32 +++++++++++++++++--------------- video/out/vo.h | 21 +++++++++++++++++++-- video/out/vo_gpu.c | 7 ++++--- 7 files changed, 52 insertions(+), 36 deletions(-) diff --git a/video/out/gpu/context.h b/video/out/gpu/context.h index b6b6ffcf43..ef48e6053f 100644 --- a/video/out/gpu/context.h +++ b/video/out/gpu/context.h @@ -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 diff --git a/video/out/opengl/context.c b/video/out/opengl/context.c index 44e64b7d9a..9b3dd6a827 100644 --- a/video/out/opengl/context.c +++ b/video/out/opengl/context.c @@ -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, }; diff --git a/video/out/opengl/context.h b/video/out/opengl/context.h index feaf8e1ab6..2dd2517ef5 100644 --- a/video/out/opengl/context.h +++ b/video/out/opengl/context.h @@ -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 diff --git a/video/out/opengl/context_glx.c b/video/out/opengl/context_glx.c index fe210c5f7d..2a6a2a4cf1 100644 --- a/video/out/opengl/context_glx.c +++ b/video/out/opengl/context_glx.c @@ -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)) diff --git a/video/out/vo.c b/video/out/vo.c index 466759f595..4110e1f353 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -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) { diff --git a/video/out/vo.h b/video/out/vo.h index 848f71e472..f64d94a5ba 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -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 diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c index 3535ae3e7e..0162e420e8 100644 --- a/video/out/vo_gpu.c +++ b/video/out/vo_gpu.c @@ -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, -- cgit v1.2.3