summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2023-11-14 09:51:11 +0100
committerDudemanguy <random342@airmail.cc>2023-11-18 22:54:29 +0000
commitba5071a7ef225da20fb2a525a555ef4f6ba86049 (patch)
tree497b793614cfcf030515ccb016b0f37978c86955 /video
parentfe748e54f17051f13b651472ccda961a7cccad40 (diff)
downloadmpv-ba5071a7ef225da20fb2a525a555ef4f6ba86049.tar.bz2
mpv-ba5071a7ef225da20fb2a525a555ef4f6ba86049.tar.xz
vo_gpu_next: add validation for invalid pl_queue usage
This is mainly for debugging purposes, as it should't happen in normal use. If it does, it needs fixing.
Diffstat (limited to 'video')
-rw-r--r--video/out/vo_gpu_next.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c
index 869a11d54d..f079d7570e 100644
--- a/video/out/vo_gpu_next.c
+++ b/video/out/vo_gpu_next.c
@@ -874,6 +874,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
bool cache_frame = will_redraw || frame->still;
bool can_interpolate = opts->interpolation && frame->display_synced &&
!frame->still && frame->num_frames > 1;
+ double pts_offset = can_interpolate ? frame->ideal_frame_vsync : 0;
params.info_callback = info_callback;
params.info_priv = vo;
params.skip_caching_single_frame = !cache_frame;
@@ -881,6 +882,27 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
if (frame->still)
params.frame_mixer = NULL;
+ // pl_queue advances its internal virtual PTS and culls available frames
+ // based on this value and the VPS/FPS ratio. Requesting a non-monotonic PTS
+ // is an invalid use of pl_queue. Reset it if this happens in an attempt to
+ // recover as much as possible. Ideally, this should never occur, and if it
+ // does, it should be corrected. The ideal_frame_vsync may be negative if
+ // the last draw did not align perfectly with the vsync. In this case, we
+ // should have the previous frame available in pl_queue, or a reset is
+ // already requested. Clamp the check to 0, as we don't have the previous
+ // frame in vo_frame anyway.
+ struct pl_source_frame vpts;
+ if (frame->current && !p->want_reset) {
+ if (pl_queue_peek(p->queue, 0, &vpts) &&
+ frame->current->pts + MPMAX(0, pts_offset) < vpts.pts)
+ {
+ MP_VERBOSE(vo, "Forcing queue refill, PTS(%f + %f | %f) < VPTS(%f)\n",
+ frame->current->pts, pts_offset,
+ frame->ideal_frame_vsync_duration, vpts.pts);
+ p->want_reset = true;
+ }
+ }
+
// Push all incoming frames into the frame queue
for (int n = 0; n < frame->num_frames; n++) {
int id = frame->frame_id + n;
@@ -929,7 +951,6 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
struct pl_swapchain_frame swframe;
struct ra_swapchain *sw = p->ra_ctx->swapchain;
- double pts_offset = can_interpolate ? frame->ideal_frame_vsync : 0;
bool should_draw = sw->fns->start_frame(sw, NULL); // for wayland logic
if (!should_draw || !pl_swapchain_start_frame(p->sw, &swframe)) {
if (frame->current) {