From d7495e4ea66829be0f1c100f7ab0be0665da06f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 20 Sep 2025 20:53:59 +0200 Subject: [PATCH] vo: set swapchain-depth to 1 in display sync modes All the math and interpolation assumes immediate presentation of the frame. VO is driven by VSYNC and it is expected that current frame that we render will be displayed on current present call, without delay. --- DOCS/man/options.rst | 2 ++ video/out/d3d11/context.c | 4 ++-- video/out/drm_common.c | 2 +- video/out/gpu_next/context.c | 2 +- video/out/opengl/context.c | 2 +- video/out/opengl/context_angle.c | 4 ++-- video/out/opengl/context_drm_egl.c | 2 +- video/out/opengl/context_dxinterop.c | 4 ++-- video/out/present_sync.c | 6 +++--- video/out/present_sync.h | 4 ++-- video/out/vo.c | 7 +++++++ video/out/vo.h | 2 ++ video/out/vo_drm.c | 4 ++-- video/out/vulkan/context.c | 2 +- video/out/wayland_common.c | 2 +- video/out/x11_common.c | 2 +- 16 files changed, 31 insertions(+), 20 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 5ba0f6776a..dd359d823d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1999,6 +1999,8 @@ Video upper limit, the implementation can use a lower latency than requested internally. A setting of 1 means that the VO will wait for every frame to become visible before starting to render the next frame. (Default: 3) + If ``--video-sync=display-*`` is used, this option is ignored and the depth + is always 1. Audio ----- diff --git a/video/out/d3d11/context.c b/video/out/d3d11/context.c index 6036e7252b..6be850facd 100644 --- a/video/out/d3d11/context.c +++ b/video/out/d3d11/context.c @@ -511,7 +511,7 @@ static bool d3d11_init(struct ra_ctx *ctx) .allow_warp = p->opts->warp != 0, .force_warp = p->opts->warp == 1, .max_feature_level = p->opts->feature_level, - .max_frame_latency = ctx->vo->opts->swapchain_depth, + .max_frame_latency = vo_swapchain_depth(ctx->vo), .adapter_name = p->opts->adapter_name, }; if (!mp_d3d11_create_present_device(ctx->log, &dopts, &p->device)) @@ -550,7 +550,7 @@ static bool d3d11_init(struct ra_ctx *ctx) .flip = p->opts->flip, // Add one frame for the backbuffer and one frame of "slack" to reduce // contention with the window manager when acquiring the backbuffer - .length = ctx->vo->opts->swapchain_depth + 2, + .length = vo_swapchain_depth(ctx->vo) + 2, .usage = usage, }; if (!mp_d3d11_create_swapchain(p->device, ctx->log, &scopts, &p->swapchain)) diff --git a/video/out/drm_common.c b/video/out/drm_common.c index ffc5ebfbad..ff7d69f450 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -1137,7 +1137,7 @@ bool vo_drm_init(struct vo *vo) drm->ev.version = DRM_EVENT_CONTEXT_VERSION; drm->ev.page_flip_handler = &drm_pflip_cb; - drm->present = mp_present_initialize(drm, drm->vo->opts, VO_MAX_SWAPCHAIN_DEPTH); + drm->present = mp_present_initialize(drm, drm->vo, VO_MAX_SWAPCHAIN_DEPTH); return true; diff --git a/video/out/gpu_next/context.c b/video/out/gpu_next/context.c index 2c7c9fa21e..b4bfa9d643 100644 --- a/video/out/gpu_next/context.c +++ b/video/out/gpu_next/context.c @@ -161,7 +161,7 @@ struct gpu_ctx *gpu_ctx_create(struct vo *vo, struct ra_ctx_opts *ctx_opts) mppl_log_set_probing(ctx->pllog, false); ctx->swapchain = pl_opengl_create_swapchain(opengl, pl_opengl_swapchain_params( - .max_swapchain_depth = vo->opts->swapchain_depth, + .max_swapchain_depth = vo_swapchain_depth(vo), .framebuffer.flipped = gl->flipped, )); if (!ctx->swapchain) diff --git a/video/out/opengl/context.c b/video/out/opengl/context.c index 86e8d5daac..28226fd90d 100644 --- a/video/out/opengl/context.c +++ b/video/out/opengl/context.c @@ -290,7 +290,7 @@ void ra_gl_ctx_swap_buffers(struct ra_swapchain *sw) check_pattern(p, step); } - while (p->num_vsync_fences >= sw->ctx->vo->opts->swapchain_depth) { + while (p->num_vsync_fences >= vo_swapchain_depth(sw->ctx->vo)) { gl->ClientWaitSync(p->vsync_fences[0], GL_SYNC_FLUSH_COMMANDS_BIT, 1e9); gl->DeleteSync(p->vsync_fences[0]); MP_TARRAY_REMOVE_AT(p->vsync_fences, p->num_vsync_fences, 0); diff --git a/video/out/opengl/context_angle.c b/video/out/opengl/context_angle.c index e635836ee3..75e37dab0e 100644 --- a/video/out/opengl/context_angle.c +++ b/video/out/opengl/context_angle.c @@ -225,7 +225,7 @@ static bool d3d11_device_create(struct ra_ctx *ctx) .force_warp = o->d3d11_warp == 1, .max_feature_level = o->d3d11_feature_level, .min_feature_level = D3D_FEATURE_LEVEL_9_3, - .max_frame_latency = ctx->vo->opts->swapchain_depth, + .max_frame_latency = vo_swapchain_depth(ctx->vo), }; if (!mp_d3d11_create_present_device(vo->log, &device_opts, &p->d3d11_device)) return false; @@ -293,7 +293,7 @@ static bool d3d11_swapchain_surface_create(struct ra_ctx *ctx) .flip = o->flip, // Add one frame for the backbuffer and one frame of "slack" to reduce // contention with the window manager when acquiring the backbuffer - .length = ctx->vo->opts->swapchain_depth + 2, + .length = vo_swapchain_depth(ctx->vo) + 2, .usage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT, }; if (!mp_d3d11_create_swapchain(p->d3d11_device, vo->log, &swapchain_opts, diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c index fc78f13f0e..ef3f83436c 100644 --- a/video/out/opengl/context_drm_egl.c +++ b/video/out/opengl/context_drm_egl.c @@ -385,7 +385,7 @@ static void drm_egl_swap_buffers(struct ra_ctx *ctx) } enqueue_bo(ctx, new_bo); - while (drm->redraw || p->gbm.num_bos > ctx->vo->opts->swapchain_depth || + while (drm->redraw || p->gbm.num_bos > vo_swapchain_depth(ctx->vo) || !gbm_surface_has_free_buffers(p->gbm.surface)) { if (drm->waiting_for_flip) { vo_drm_wait_on_flip(drm); diff --git a/video/out/opengl/context_dxinterop.c b/video/out/opengl/context_dxinterop.c index c8640ea8f6..6aa5fe462a 100644 --- a/video/out/opengl/context_dxinterop.c +++ b/video/out/opengl/context_dxinterop.c @@ -341,7 +341,7 @@ static void fill_presentparams(struct ra_ctx *ctx, .BackBufferHeight = ctx->vo->dheight ? ctx->vo->dheight : 1, // Add one frame for the backbuffer and one frame of "slack" to reduce // contention with the window manager when acquiring the backbuffer - .BackBufferCount = ctx->vo->opts->swapchain_depth + 2, + .BackBufferCount = vo_swapchain_depth(ctx->vo) + 2, .SwapEffect = IsWindows7OrGreater() ? D3DSWAPEFFECT_FLIPEX : D3DSWAPEFFECT_FLIP, // Automatically get the backbuffer format from the display format .BackBufferFormat = D3DFMT_UNKNOWN, @@ -393,7 +393,7 @@ static int d3d_create(struct ra_ctx *ctx) return -1; } - IDirect3DDevice9Ex_SetMaximumFrameLatency(p->device, ctx->vo->opts->swapchain_depth); + IDirect3DDevice9Ex_SetMaximumFrameLatency(p->device, vo_swapchain_depth(ctx->vo)); // Register the Direct3D device with WGL_NV_dx_interop p->device_h = gl->DXOpenDeviceNV(p->device); diff --git a/video/out/present_sync.c b/video/out/present_sync.c index a3b1089f1a..ce289cb04e 100644 --- a/video/out/present_sync.c +++ b/video/out/present_sync.c @@ -57,14 +57,14 @@ void present_sync_get_info(struct mp_present *present, struct vo_vsync_info *inf LL_APPEND(list_node, present, cur); } -struct mp_present *mp_present_initialize(void *talloc_ctx, struct mp_vo_opts *opts, int entries) +struct mp_present *mp_present_initialize(void *talloc_ctx, struct vo *vo, int entries) { struct mp_present *present = talloc_zero(talloc_ctx, struct mp_present); for (int i = 0; i < entries; i++) { struct mp_present_entry *entry = talloc_zero(present, struct mp_present_entry); LL_APPEND(list_node, present, entry); } - present->opts = opts; + present->vo = vo; return present; } @@ -114,7 +114,7 @@ void present_sync_update_values(struct mp_present *present, int64_t ust, struct mp_present_entry *cur = present->head; int index = 0; while (cur && ++index) { - if (!cur->ust || index == present->opts->swapchain_depth) + if (!cur->ust || index == vo_swapchain_depth(present->vo)) break; cur = cur->list_node.next; } diff --git a/video/out/present_sync.h b/video/out/present_sync.h index ba6d0b3bf4..04329ea6a1 100644 --- a/video/out/present_sync.h +++ b/video/out/present_sync.h @@ -39,10 +39,10 @@ struct mp_present_entry { struct mp_present { struct mp_present_entry *head, *tail; - struct mp_vo_opts *opts; + struct vo *vo; }; -struct mp_present *mp_present_initialize(void *talloc_ctx, struct mp_vo_opts *opts, int entries); +struct mp_present *mp_present_initialize(void *talloc_ctx, struct vo *vo, int entries); // Used during the get_vsync call to deliver the presentation statistics to the VO. void present_sync_get_info(struct mp_present *present, struct vo_vsync_info *info); diff --git a/video/out/vo.c b/video/out/vo.c index 465aa54ff1..97a9dd617a 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -1533,3 +1533,10 @@ struct mp_image_params vo_get_target_params(struct vo *vo) mp_mutex_unlock(&vo->params_mutex); return p; } + +int vo_swapchain_depth(struct vo *vo) +{ + if (!VS_IS_DISP(vo->opts->video_sync)) + return vo->opts->swapchain_depth; + return 1; +} diff --git a/video/out/vo.h b/video/out/vo.h index bef624296f..f9629337fe 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -578,4 +578,6 @@ struct vo_frame *vo_frame_ref(struct vo_frame *frame); struct mp_image_params vo_get_current_params(struct vo *vo); struct mp_image_params vo_get_target_params(struct vo *vo); +int vo_swapchain_depth(struct vo *vo); + #endif /* MPLAYER_VIDEO_OUT_H */ diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index 7a069b8f35..0ec792f8ba 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -343,7 +343,7 @@ static void flip_page(struct vo *vo) if (!drm->active) return; - while (drm->redraw || p->fb_queue_len > vo->opts->swapchain_depth) { + while (drm->redraw || p->fb_queue_len > vo_swapchain_depth(vo)) { if (drm->waiting_for_flip) { vo_drm_wait_on_flip(vo->drm); swapchain_step(vo); @@ -389,7 +389,7 @@ static int preinit(struct vo *vo) goto err; struct vo_drm_state *drm = vo->drm; - p->buf_count = vo->opts->swapchain_depth + 1; + p->buf_count = vo_swapchain_depth(vo) + 1; p->bufs = talloc_zero_array(p, struct framebuffer *, p->buf_count); p->front_buf = 0; diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c index 7c196eb3fe..ac2c31c32f 100644 --- a/video/out/vulkan/context.c +++ b/video/out/vulkan/context.c @@ -419,7 +419,7 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk, struct pl_vulkan_swapchain_params pl_params = { .surface = vk->surface, .present_mode = preferred_mode, - .swapchain_depth = ctx->vo->opts->swapchain_depth, + .swapchain_depth = vo_swapchain_depth(ctx->vo), }; if (p->opts->swap_mode >= 0) // user override diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index ed4711050c..50962106c0 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -4309,7 +4309,7 @@ bool vo_wayland_init(struct vo *vo) wl->fback_pool->len = VO_MAX_SWAPCHAIN_DEPTH; wl->fback_pool->fback = talloc_zero_array(wl->fback_pool, struct wp_presentation_feedback *, wl->fback_pool->len); - wl->present = mp_present_initialize(wl, wl->opts, VO_MAX_SWAPCHAIN_DEPTH); + wl->present = mp_present_initialize(wl, wl->vo, VO_MAX_SWAPCHAIN_DEPTH); } else { MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n", wp_presentation_interface.name); diff --git a/video/out/x11_common.c b/video/out/x11_common.c index 7099199e3a..49a8ddf7d7 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -695,7 +695,7 @@ bool vo_x11_init(struct vo *vo) x11_error_output = x11->log; XSetErrorHandler(x11_errorhandler); - x11->present = mp_present_initialize(x11, x11->opts, VO_MAX_SWAPCHAIN_DEPTH); + x11->present = mp_present_initialize(x11, vo, VO_MAX_SWAPCHAIN_DEPTH); dispName = XDisplayName(NULL);