From 91c1b65de09fb8b449fb6ffef32c120ba6325e7e Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Fri, 20 Dec 2024 12:24:38 -0600 Subject: [PATCH] vo: change draw_frame API to a boolean x11 and wayland VOs + backends all have logic that skips drawing frames when the mpv isn't visible for efficiency reasons. This is implemented in each individual VO, but it is useful for the core to be aware of this as well. Currently, the display-sync modes on x11 do not try to be efficient and always render anyways because there is no blocking on the graphics API level if you skip rendering a frame (wayland works here by accident). This means mpv would otherwise blaze through frames which is not what anyone wants. We can instead improve this by implementing the blocking mechanism in the core and using that when appropriate. This commit does not implement that yet, but simply switches the draw_frame to a boolean. Receiving false means that the VO is not drawing frames and it should be treated as if the surface was hidden. --- video/out/vo.h | 6 +++++- video/out/vo_caca.c | 7 +++++-- video/out/vo_direct3d.c | 11 +++++++---- video/out/vo_dmabuf_wayland.c | 6 ++++-- video/out/vo_drm.c | 7 +++++-- video/out/vo_gpu.c | 8 +++++--- video/out/vo_gpu_next.c | 5 +++-- video/out/vo_image.c | 7 +++++-- video/out/vo_kitty.c | 7 +++++-- video/out/vo_lavc.c | 9 ++++++--- video/out/vo_libmpv.c | 3 ++- video/out/vo_mediacodec_embed.c | 3 ++- video/out/vo_null.c | 3 ++- video/out/vo_sdl.c | 7 +++++-- video/out/vo_sixel.c | 9 ++++++--- video/out/vo_tct.c | 7 +++++-- video/out/vo_vaapi.c | 7 +++++-- video/out/vo_vdpau.c | 3 ++- video/out/vo_wlshm.c | 9 ++++++--- video/out/vo_x11.c | 6 ++++-- video/out/vo_xv.c | 6 ++++-- 21 files changed, 93 insertions(+), 43 deletions(-) diff --git a/video/out/vo.h b/video/out/vo.h index a3b2ac1556..77efe7f58a 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -407,8 +407,12 @@ struct vo_driver { * frame is freed by the caller if the callee did not assume ownership * of the frames, but in any case the callee can still modify the * contained data and references. + * + * Return false to signal to the core that rendering is being skipped for + * this particular frame. vo.c will sleep for the expected duration of that + * frame before advancing forward. */ - void (*draw_frame)(struct vo *vo, struct vo_frame *frame); + bool (*draw_frame)(struct vo *vo, struct vo_frame *frame); /* * Blit/Flip buffer to the screen. Must be called after each frame! diff --git a/video/out/vo_caca.c b/video/out/vo_caca.c index 0625de0e5f..8ce4322a4e 100644 --- a/video/out/vo_caca.c +++ b/video/out/vo_caca.c @@ -111,15 +111,18 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) return resize(vo); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *priv = vo->priv; struct mp_image *mpi = frame->current; if (!mpi) - return; + goto done; memcpy_pic(priv->dither_buffer, mpi->planes[0], priv->image_width * depth, priv->image_height, priv->image_width * depth, mpi->stride[0]); caca_dither_bitmap(priv->canvas, 0, 0, priv->screen_w, priv->screen_h, priv->dither, priv->dither_buffer); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c index 91e962faa1..e3a5fc5417 100644 --- a/video/out/vo_direct3d.c +++ b/video/out/vo_direct3d.c @@ -1003,18 +1003,18 @@ static bool get_video_buffer(d3d_priv *priv, struct mp_image *out) return true; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { d3d_priv *priv = vo->priv; if (!priv->d3d_device) - return; + goto done; struct mp_image buffer; if (!get_video_buffer(priv, &buffer)) - return; + goto done; if (!frame->current) - return; + goto done; mp_image_copy(&buffer, frame->current); @@ -1024,6 +1024,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) priv->osd_pts = frame->current->pts; d3d_draw_frame(priv); + +done: + return VO_TRUE; } static mp_image_t *get_window_screenshot(d3d_priv *priv) diff --git a/video/out/vo_dmabuf_wayland.c b/video/out/vo_dmabuf_wayland.c index 733a011cd9..1a12c32ddb 100644 --- a/video/out/vo_dmabuf_wayland.c +++ b/video/out/vo_dmabuf_wayland.c @@ -592,7 +592,7 @@ done: return draw; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; struct vo_wayland_state *wl = vo->wl; @@ -603,7 +603,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (!vo_wayland_check_visible(vo)) { if (frame->current) talloc_free(frame); - return; + return VO_FALSE; } if (p->destroy_buffers) @@ -641,6 +641,8 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) p->osd_surface_is_mapped = false; } } + + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index 34726a3c02..cf8c6a8ee1 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -300,13 +300,13 @@ static void swapchain_step(struct vo *vo) } } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct vo_drm_state *drm = vo->drm; struct priv *p = vo->priv; if (!drm->active) - return; + goto done; drm->still = frame->still; @@ -319,6 +319,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) } enqueue_frame(vo, fb); + +done: + return VO_TRUE; } static void queue_flip(struct vo *vo, struct drm_frame *frame) diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c index 837292b248..53b0fb4087 100644 --- a/video/out/vo_gpu.c +++ b/video/out/vo_gpu.c @@ -70,25 +70,27 @@ static void resize(struct vo *vo) vo->want_redraw = true; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct gpu_priv *p = vo->priv; struct ra_swapchain *sw = p->ctx->swapchain; struct ra_fbo fbo; if (!sw->fns->start_frame(sw, &fbo)) - return; + return VO_FALSE; gl_video_render_frame(p->renderer, frame, &fbo, RENDER_FRAME_DEF); if (!sw->fns->submit_frame(sw, frame)) { MP_ERR(vo, "Failed presenting frame!\n"); - return; + return VO_FALSE; } struct mp_image_params *params = gl_video_get_target_params_ptr(p->renderer); mp_mutex_lock(&vo->params_mutex); vo->target_params = params; mp_mutex_unlock(&vo->params_mutex); + + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 9706e92f0a..118df140fc 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -904,7 +904,7 @@ static void update_tm_viz(struct pl_color_map_params *params, static void update_hook_opts_dynamic(struct priv *p, const struct pl_hook *hook, const struct mp_image *mpi); -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; pl_options pars = p->pars; @@ -1029,7 +1029,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) #endif pl_queue_update(p->queue, NULL, &qparams); } - return; + return VO_FALSE; } bool valid = false; @@ -1173,6 +1173,7 @@ done: pl_gpu_flush(gpu); p->frame_pending = true; + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_image.c b/video/out/vo_image.c index 84e164f6e5..ea289dcea6 100644 --- a/video/out/vo_image.c +++ b/video/out/vo_image.c @@ -90,16 +90,19 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) return 0; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; if (!frame->current) - return; + goto done; p->current = frame->current; struct mp_osd_res dim = osd_res_from_image_params(vo->params); osd_draw_on_image(vo->osd, dim, frame->current->pts, OSD_DRAW_SUB_ONLY, p->current); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_kitty.c b/video/out/vo_kitty.c index a5f716a0bd..208f2b6d2d 100644 --- a/video/out/vo_kitty.c +++ b/video/out/vo_kitty.c @@ -239,7 +239,7 @@ static int create_shm(struct vo *vo) #endif } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; mp_image_t *mpi = NULL; @@ -273,7 +273,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (p->opts.use_shm && !create_shm(vo)) - return; + goto done; memcpy_pic(p->buffer, p->frame->planes[0], p->width * BYTES_PER_PX, p->height, p->width * BYTES_PER_PX, p->frame->stride[0]); @@ -282,6 +282,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) av_base64_encode(p->output, p->output_size, p->buffer, p->buffer_size); talloc_free(mpi); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c index 8e643c65a8..839c9f7db4 100644 --- a/video/out/vo_lavc.c +++ b/video/out/vo_lavc.c @@ -182,7 +182,7 @@ static int query_format(struct vo *vo, int format) return 0; } -static void draw_frame(struct vo *vo, struct vo_frame *voframe) +static bool draw_frame(struct vo *vo, struct vo_frame *voframe) { struct priv *vc = vo->priv; struct encoder_context *enc = vc->enc; @@ -190,7 +190,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *voframe) AVCodecContext *avc = enc->encoder; if (voframe->redraw || voframe->repeat || voframe->num_frames < 1) - return; + goto done; struct mp_image *mpi = voframe->frames[0]; @@ -198,7 +198,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *voframe) osd_draw_on_image(vo->osd, dim, mpi->pts, OSD_DRAW_SUB_ONLY, mpi); if (vc->shutdown) - return; + goto done; // Lock for shared timestamp fields. mp_mutex_lock(&ectx->lock); @@ -241,6 +241,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *voframe) frame->quality = avc->global_quality; encoder_encode(enc, frame); av_frame_free(&frame); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_libmpv.c b/video/out/vo_libmpv.c index 7974eed3f7..a42cfa65ca 100644 --- a/video/out/vo_libmpv.c +++ b/video/out/vo_libmpv.c @@ -485,7 +485,7 @@ int mpv_render_context_get_info(mpv_render_context *ctx, return res; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct vo_priv *p = vo->priv; struct mpv_render_context *ctx = p->ctx; @@ -498,6 +498,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) mp_mutex_unlock(&ctx->lock); update(ctx); + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_mediacodec_embed.c b/video/out/vo_mediacodec_embed.c index 08d3866d57..00ac659f62 100644 --- a/video/out/vo_mediacodec_embed.c +++ b/video/out/vo_mediacodec_embed.c @@ -76,7 +76,7 @@ static void flip_page(struct vo *vo) mp_image_unrefp(&p->next_image); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; @@ -86,6 +86,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) talloc_free(p->next_image); p->next_image = mpi; + return VO_TRUE; } static int query_format(struct vo *vo, int format) diff --git a/video/out/vo_null.c b/video/out/vo_null.c index 0c49062e23..bf2ce0b775 100644 --- a/video/out/vo_null.c +++ b/video/out/vo_null.c @@ -32,8 +32,9 @@ struct priv { double cfg_fps; }; -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c index cce07d3d7d..d1e3734e35 100644 --- a/video/out/vo_sdl.c +++ b/video/out/vo_sdl.c @@ -879,7 +879,7 @@ static int query_format(struct vo *vo, int format) return 0; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *vc = vo->priv; @@ -894,7 +894,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) mp_image_t texmpi; if (!lock_texture(vo, &texmpi)) - return; + goto done; mp_image_copy(&texmpi, frame->current); @@ -914,6 +914,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) SDL_RenderCopy(vc->renderer, vc->tex, &src, &dst); draw_osd(vo); + +done: + return VO_TRUE; } static struct mp_image *get_window_screenshot(struct vo *vo) diff --git a/video/out/vo_sixel.c b/video/out/vo_sixel.c index f4ad675540..9d58a0a4a3 100644 --- a/video/out/vo_sixel.c +++ b/video/out/vo_sixel.c @@ -378,7 +378,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) return ret; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *priv = vo->priv; SIXELSTATUS status; @@ -391,7 +391,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) bool resized = false; update_canvas_dimensions(vo); if (!priv->canvas_ok) - return; + goto done; if (prev_rows != priv->num_rows || prev_cols != priv->num_cols || prev_width != vo->dwidth || prev_height != vo->dheight) @@ -409,7 +409,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (frame->repeat && !frame->redraw && !resized) { // Frame is repeated, and no need to update OSD either priv->skip_frame_draw = true; - return; + goto done; } else { // Either frame is new, or OSD has to be redrawn priv->skip_frame_draw = false; @@ -457,6 +457,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (mpi) talloc_free(mpi); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_tct.c b/video/out/vo_tct.c index f42e568831..07aefe4b3d 100644 --- a/video/out/vo_tct.c +++ b/video/out/vo_tct.c @@ -253,14 +253,17 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) return 0; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; struct mp_image *src = frame->current; if (!src) - return; + goto done; // XXX: pan, crop etc. mp_sws_scale(p->sws, p->frame, src); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 84ca4a7a42..cb8b1560c5 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -555,7 +555,7 @@ static void get_vsync(struct vo *vo, struct vo_vsync_info *info) present_sync_get_info(x11->present, info); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; struct mp_image *mpi = frame->current; @@ -564,7 +564,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) struct mp_image *dst = p->swdec_surfaces[p->output_surface]; if (!dst || va_surface_upload(p, dst, mpi) < 0) { MP_WARN(vo, "Could not upload surface.\n"); - return; + goto done; } mp_image_copy_attributes(dst, mpi); mpi = dst; @@ -573,6 +573,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) p->output_surfaces[p->output_surface] = mpi; draw_osd(vo); + +done: + return VO_TRUE; } static void free_subpicture(struct priv *p, struct vaapi_osd_image *img) diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index b22dcba0ce..4b28106624 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -870,7 +870,7 @@ drop: vo_increment_drop_count(vo, 1); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct vdpctx *vc = vo->priv; @@ -893,6 +893,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) video_to_output_surface(vo, vc->current_image); draw_osd(vo); } + return VO_TRUE; } // warning: the size and pixel format of surface must match that of the diff --git a/video/out/vo_wlshm.c b/video/out/vo_wlshm.c index 3132d7a563..708963e55a 100644 --- a/video/out/vo_wlshm.c +++ b/video/out/vo_wlshm.c @@ -239,7 +239,7 @@ static int control(struct vo *vo, uint32_t request, void *data) return ret; } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; struct vo_wayland_state *wl = vo->wl; @@ -248,7 +248,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) bool render = vo_wayland_check_visible(vo); if (!render) - return; + return VO_FALSE; buf = p->free_buffers; if (buf) { @@ -257,7 +257,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) buf = buffer_create(vo, vo->dwidth, vo->dheight); if (!buf) { wl_surface_attach(wl->surface, NULL, 0, 0); - return; + goto done; } } if (src) { @@ -289,6 +289,9 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) osd_draw_on_image(vo->osd, p->osd, 0, 0, &buf->mpi); } wl_surface_attach(wl->surface, buf->buffer, 0, 0); + +done: + return VO_TRUE; } static void flip_page(struct vo *vo) diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c index b637b59e23..8391b431f4 100644 --- a/video/out/vo_x11.c +++ b/video/out/vo_x11.c @@ -327,14 +327,14 @@ static void get_vsync(struct vo *vo, struct vo_vsync_info *info) present_sync_get_info(x11->present, info); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct priv *p = vo->priv; wait_for_completion(vo, 1); bool render = vo_x11_check_visible(vo); if (!render) - return; + return VO_FALSE; struct mp_image *img = &p->mp_ximages[p->current_buf]; @@ -359,6 +359,8 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (frame->current != p->original_image) p->original_image = frame->current; + + return VO_TRUE; } static int query_format(struct vo *vo, int format) diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index 38b903a72f..ecd6e34477 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -708,14 +708,14 @@ static void get_vsync(struct vo *vo, struct vo_vsync_info *info) present_sync_get_info(x11->present, info); } -static void draw_frame(struct vo *vo, struct vo_frame *frame) +static bool draw_frame(struct vo *vo, struct vo_frame *frame) { struct xvctx *ctx = vo->priv; wait_for_completion(vo, ctx->num_buffers - 1); bool render = vo_x11_check_visible(vo); if (!render) - return; + return VO_FALSE; struct mp_image xv_buffer = get_xv_buffer(vo, ctx->current_buf); if (frame->current) { @@ -729,6 +729,8 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame) if (frame->current != ctx->original_image) ctx->original_image = frame->current; + + return VO_TRUE; } static int query_format(struct vo *vo, int format)