summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2022-02-15 12:47:53 +0100
committerNiklas Haas <github-daiK1o@haasn.dev>2022-02-21 12:01:44 +0100
commitfbe154831a8addfc18a4f81e1c4b9284c31acace (patch)
tree1aca46bd7926589269894ec0216b53f4807a4936
parent27c38eac1040cd781f39d977ce53adcd65ddcfb6 (diff)
downloadmpv-fbe154831a8addfc18a4f81e1c4b9284c31acace.tar.bz2
mpv-fbe154831a8addfc18a4f81e1c4b9284c31acace.tar.xz
vo_gpu_next: refactor subtitle rendering
Render subs at the output resolution, rather than the video resolution. Uses the new APIs found in libplacebo 197+, to allow controlling the OSD resolution even for image-attached overlays. Also fixes an issue where the overlay state did not get correctly updated while paused. To avoid regenerating the OSD / flushing the cache constantly, we keep track of OSD changes and only regenerate the OSD when the OSD state is expected to change in some way (e.g. resolution change). This requires introducing a new VOCTRL to inform the VO when the UPDATE_OSD-tagged options have changed. Fixes #9744, #9524, #9399 and #9398.
-rw-r--r--meson.build6
-rw-r--r--player/command.c2
-rw-r--r--video/out/vo.c1
-rw-r--r--video/out/vo.h3
-rw-r--r--video/out/vo_gpu_next.c82
-rw-r--r--wscript4
6 files changed, 63 insertions, 35 deletions
diff --git a/meson.build b/meson.build
index 598e830725..10cfa54a90 100644
--- a/meson.build
+++ b/meson.build
@@ -965,14 +965,14 @@ if libplacebo.found()
sources += files('video/out/placebo/ra_pl.c',
'video/out/placebo/utils.c')
pl_api_ver = libplacebo.version().split('.')[1]
- if pl_api_ver.version_compare('>=190')
+ if pl_api_ver.version_compare('>=197')
features += 'libplacebo-next'
libplacebo_next = true
- message('libplacebo v4.190+ found! Enabling vo_gpu_next.')
+ message('libplacebo v4.197+ found! Enabling vo_gpu_next.')
sources += files('video/out/vo_gpu_next.c',
'video/out/gpu_next/context.c')
else
- message('libplacebo v4.190+ not found! Disabling vo_gpu_next.')
+ message('libplacebo v4.197+ not found! Disabling vo_gpu_next.')
endif
endif
diff --git a/player/command.c b/player/command.c
index 4f2eb4741d..2b4650e062 100644
--- a/player/command.c
+++ b/player/command.c
@@ -6619,6 +6619,8 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags,
}
}
osd_changed(mpctx->osd);
+ if (mpctx->video_out)
+ vo_control_async(mpctx->video_out, VOCTRL_OSD_CHANGED, NULL);
if (flags & (UPDATE_SUB_FILT | UPDATE_SUB_HARD))
mp_force_video_refresh(mpctx);
mp_wakeup_core(mpctx);
diff --git a/video/out/vo.c b/video/out/vo.c
index 253cb6274a..11ef596227 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -678,6 +678,7 @@ void vo_control_async(struct vo *vo, int request, void *data)
break;
case VOCTRL_KILL_SCREENSAVER:
case VOCTRL_RESTORE_SCREENSAVER:
+ case VOCTRL_OSD_CHANGED:
break;
default:
abort(); // requires explicit support
diff --git a/video/out/vo.h b/video/out/vo.h
index a8e8b9ddaf..63d6c7caa7 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -72,6 +72,9 @@ enum mp_voctrl {
// you could install your own listener.
VOCTRL_VO_OPTS_CHANGED,
+ // Triggered by any change to the OSD (e.g. OSD style changes)
+ VOCTRL_OSD_CHANGED,
+
/* private to vo_gpu */
VOCTRL_LOAD_HWDEC_API,
diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c
index da613f498b..67e44e90cd 100644
--- a/video/out/vo_gpu_next.c
+++ b/video/out/vo_gpu_next.c
@@ -90,6 +90,7 @@ struct priv {
struct osd_state osd_state;
uint64_t last_id;
+ uint64_t osd_sync;
double last_pts;
bool is_interpolated;
bool want_reset;
@@ -208,9 +209,9 @@ static struct mp_image *get_image(struct vo *vo, int imgfmt, int w, int h,
return mpi;
}
-static void write_overlays(struct vo *vo, struct mp_osd_res res, double pts,
- int flags, struct osd_state *state,
- struct pl_frame *frame, bool flip)
+static void update_overlays(struct vo *vo, struct mp_osd_res res, double pts,
+ int flags, struct osd_state *state,
+ struct pl_frame *frame, bool flip)
{
struct priv *p = vo->priv;
static const bool subfmt_all[SUBBITMAP_COUNT] = {
@@ -219,8 +220,8 @@ static void write_overlays(struct vo *vo, struct mp_osd_res res, double pts,
};
struct sub_bitmap_list *subs = osd_render(vo->osd, res, pts, flags, subfmt_all);
- frame->num_overlays = 0;
frame->overlays = state->overlays;
+ frame->num_overlays = 0;
for (int n = 0; n < subs->num_items; n++) {
const struct sub_bitmaps *item = subs->items[n];
@@ -280,6 +281,7 @@ static void write_overlays(struct vo *vo, struct mp_osd_res res, double pts,
.parts = entry->parts,
.num_parts = entry->num_parts,
.color = frame->color,
+ .coords = PL_OVERLAY_COORDS_DST_FRAME,
};
switch (item->format) {
@@ -300,6 +302,7 @@ static void write_overlays(struct vo *vo, struct mp_osd_res res, double pts,
struct frame_priv {
struct vo *vo;
struct osd_state subs;
+ uint64_t osd_sync;
};
static int plane_data_from_imgfmt(struct pl_plane_data out_data[4],
@@ -553,14 +556,6 @@ static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src
// still images so it shouldn't matter.
pl_icc_profile_compute_signature(&frame->profile);
- // Generate subtitles for this frame
- struct mp_osd_res vidres = {
- .w = mpi->w, .h = mpi->h,
- // compensate for anamorphic sources (render subtitles as normal)
- .display_par = (float) par->p_h / par->p_w,
- };
- write_overlays(vo, vidres, mpi->pts, OSD_DRAW_SUB_ONLY, &fp->subs, frame, false);
-
// Update LUT attached to this frame
update_lut(p, &p->image_lut);
frame->lut = p->image_lut.lut;
@@ -768,7 +763,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
struct pl_frame target;
pl_frame_from_swapchain(&target, &swframe);
apply_target_options(p, &target);
- write_overlays(vo, p->osd_res, 0, OSD_DRAW_OSD_ONLY, &p->osd_state, &target, swframe.flipped);
+ update_overlays(vo, p->osd_res, 0, OSD_DRAW_OSD_ONLY, &p->osd_state, &target, swframe.flipped);
apply_crop(&target, p->dst, swframe.fbo->params.w, swframe.fbo->params.h);
if (swframe.flipped)
MPSWAP(float, target.crop.y0, target.crop.y1);
@@ -800,13 +795,22 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
break;
}
- // Update source crop on all existing frames. We technically own the
- // `pl_frame` struct so this is kosher. This could be avoided by
- // instead flushing the queue on resizes, but doing it this way avoids
- // unnecessarily re-uploading frames.
+ // Update source crop and overlays on all existing frames. We
+ // technically own the `pl_frame` struct so this is kosher. This could
+ // be partially avoided by instead flushing the queue on resizes, but
+ // doing it this way avoids unnecessarily re-uploading frames.
for (int i = 0; i < mix.num_frames; i++) {
- apply_crop((struct pl_frame *) mix.frames[i], p->src,
- vo->params->w, vo->params->h);
+ struct pl_frame *image = (struct pl_frame *) mix.frames[i];
+ struct mp_image *mpi = image->user_data;
+ struct frame_priv *fp = mpi->priv;
+ apply_crop(image, p->src, vo->params->w, vo->params->h);
+
+ if (fp->osd_sync < p->osd_sync) {
+ // Only update the overlays if the state has changed
+ update_overlays(vo, p->osd_res, mpi->pts, OSD_DRAW_SUB_ONLY,
+ &fp->subs, image, false);
+ fp->osd_sync = p->osd_sync;
+ }
}
}
@@ -872,9 +876,22 @@ static int query_format(struct vo *vo, int format)
static void resize(struct vo *vo)
{
struct priv *p = vo->priv;
- vo_get_src_dst_rects(vo, &p->src, &p->dst, &p->osd_res);
+ struct mp_rect src, dst;
+ struct mp_osd_res osd;
+ vo_get_src_dst_rects(vo, &src, &dst, &osd);
gpu_ctx_resize(p->context, vo->dwidth, vo->dheight);
vo->want_redraw = true;
+
+ if (mp_rect_equals(&p->src, &src) &&
+ mp_rect_equals(&p->dst, &dst) &&
+ osd_res_equals(p->osd_res, osd))
+ return;
+
+ pl_renderer_flush_cache(p->rr);
+ p->osd_sync++;
+ p->osd_res = osd;
+ p->src = src;
+ p->dst = dst;
}
static int reconfig(struct vo *vo, struct mp_image_params *params)
@@ -950,10 +967,6 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
// the resulting mix is the correct frame for this PTS
struct pl_frame *image = (struct pl_frame *) mix.frames[0];
struct mp_image *mpi = image->user_data;
- int orig_overlays = image->num_overlays;
- if (!args->subs)
- image->num_overlays = 0;
-
struct mp_rect src = p->src, dst = p->dst;
struct mp_osd_res osd = p->osd_res;
if (!args->scaled) {
@@ -989,7 +1002,7 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
if (!fbo) {
MP_ERR(vo, "Failed creating target FBO for screenshot!\n");
- goto done;
+ return;
}
struct pl_frame target = {
@@ -1004,8 +1017,13 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
apply_target_options(p, &target);
apply_crop(image, src, mpi->params.w, mpi->params.h);
apply_crop(&target, dst, fbo->params.w, fbo->params.h);
- if (args->osd)
- write_overlays(vo, osd, 0, OSD_DRAW_OSD_ONLY, &p->osd_state, &target, false);
+
+ int osd_flags = 0;
+ if (!args->subs)
+ osd_flags |= OSD_DRAW_OSD_ONLY;
+ if (!args->osd)
+ osd_flags |= OSD_DRAW_SUB_ONLY;
+ update_overlays(vo, osd, 0, osd_flags, &p->osd_state, &target, false);
if (!pl_render_image_mix(p->rr, &mix, &target, &p->params)) {
MP_ERR(vo, "Failed rendering frame!\n");
@@ -1028,7 +1046,6 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
// fall through
done:
pl_tex_destroy(gpu, &fbo);
- image->num_overlays = orig_overlays;
}
static int control(struct vo *vo, uint32_t request, void *data)
@@ -1037,15 +1054,19 @@ static int control(struct vo *vo, uint32_t request, void *data)
switch (request) {
case VOCTRL_SET_PANSCAN:
- pl_renderer_flush_cache(p->rr); // invalidate source crop
resize(vo);
- // fall through
+ return VO_TRUE;
case VOCTRL_SET_EQUALIZER:
case VOCTRL_PAUSE:
if (p->is_interpolated)
vo->want_redraw = true;
return VO_TRUE;
+ case VOCTRL_OSD_CHANGED:
+ pl_renderer_flush_cache(p->rr);
+ p->osd_sync++;
+ return VO_TRUE;
+
case VOCTRL_UPDATE_RENDER_OPTS: {
m_config_cache_update(p->opts_cache);
const struct gl_video_opts *opts = p->opts_cache->opts;
@@ -1184,6 +1205,7 @@ static int preinit(struct vo *vo)
p->queue = pl_queue_create(p->gpu);
p->osd_fmt[SUBBITMAP_LIBASS] = pl_find_named_fmt(p->gpu, "r8");
p->osd_fmt[SUBBITMAP_BGRA] = pl_find_named_fmt(p->gpu, "bgra8");
+ p->osd_sync = 1;
char *cache_file = get_cache_file(p);
if (cache_file) {
diff --git a/wscript b/wscript
index 58ed8e5f39..a3152aa3b0 100644
--- a/wscript
+++ b/wscript
@@ -741,9 +741,9 @@ video_output_features = [
'func': check_pkg_config('libplacebo >= 4.157.0'),
}, {
'name': 'libplacebo-next',
- 'desc': 'libplacebo v4.190+, needed for vo_gpu_next',
+ 'desc': 'libplacebo v4.197+, needed for vo_gpu_next',
'deps': 'libplacebo',
- 'func': check_preprocessor('libplacebo/config.h', 'PL_API_VER >= 190',
+ 'func': check_preprocessor('libplacebo/config.h', 'PL_API_VER >= 197',
use='libplacebo'),
}, {
'name': '--vulkan',