From a9cb2e2821adb40e7548e8233390e79706104041 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Mon, 3 Jan 2022 03:56:36 +0100 Subject: vo_gpu_next: update for new tone mapping options This was significantly refactored upstream. Switch to new APIs and add new tone mapping curves and options. cf. https://code.videolan.org/videolan/libplacebo/-/merge_requests/212 --- DOCS/interface-changes.rst | 3 +++ DOCS/man/options.rst | 28 ++++++++++++++++++++++----- meson.build | 6 +++--- video/out/gpu/video.c | 44 +++++++++++++++++++++++++++++++++---------- video/out/gpu/video.h | 5 +++++ video/out/gpu/video_shaders.c | 5 +++-- video/out/vo_gpu_next.c | 33 ++++++++++++++++++-------------- 7 files changed, 90 insertions(+), 34 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index e8ad97cd55..2c59f0f6b5 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -32,6 +32,9 @@ Interface changes `--interpolation-preserve` `--lut`, `--lut-type`, `--image-lut`, `--image-lut-type` and `--target-lut` along with it. - add `--target-colorspace-hint` + - add `--tone-mapping-crosstalk` + - add `--tone-mapping` options `auto`, `spline` and `bt.2446a` + - add `--inverse-tone-mapping` --- mpv 0.34.0 --- - deprecate selecting by card number with `--drm-connector`, add `--drm-device` which can be used instead diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 000e9185e5..6742ec1a6c 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6302,6 +6302,8 @@ them. reduction (e.g. playing back BT.2020 content on a standard gamut display). Valid values are: + auto + Choose the best curve according to internal heuristics. (Default) clip Hard-clip any out-of-range values. Use this when you care about perfect color accuracy for in-range values at the cost of completely @@ -6327,13 +6329,17 @@ them. you should also enable ``--hdr-compute-peak`` for the best results. bt.2390 Perceptual tone mapping curve (EETF) specified in ITU-R Report BT.2390. - This is the recommended curve to use for typical HDR-mastered content. - (Default) gamma Fits a logarithmic transfer between the tone curves. linear Linearly stretches the entire reference gamut to (a linear multiple of) the display. + spline + Perceptually linear single-pivot polynomial. (``--vo=gpu-next`` only) + bt.2446a + HDR<->SDR mapping specified in ITU-R Report BT.2446, method A. This is + the recommended curve for well-mastered content. (``--vo=gpu-next`` + only) ``--tone-mapping-param=`` Set tone mapping parameters. By default, this is set to the special string @@ -6358,6 +6364,17 @@ them. Specifies the exponent of the function. Defaults to 1.8. linear Specifies the scale factor to use while stretching. Defaults to 1.0. + spline + Specifies the knee point (in PQ space). Defaults to 0.30. + +``--inverse-tone-mapping`` + If set, allows inverse tone mapping (expanding SDR to HDR). Not supported + by all tone mapping curves. Use with caution. (``--vo=gpu-next`` only) + +``--tone-mapping-crosstalk=<0.0..0.30>`` + If nonzero, apply an extra crosstalk matrix before tone mapping. Can help + improve the appearance of strongly saturated monochromatic highlights. + (Default: 0.04, only affects ``--vo=gpu-next``) ``--tone-mapping-max-boost=<1.0..10.0>`` Upper limit for how much the tone mapping algorithm is allowed to boost @@ -6365,7 +6382,8 @@ them. allows no additional brightness boost. A value of 2.0 would allow over-exposing by a factor of 2, and so on. Raising this setting can help reveal details that would otherwise be hidden in dark scenes, but raising - it too high will make dark scenes appear unnaturally bright. + it too high will make dark scenes appear unnaturally bright. (``-vo=gpu`` + only) ``--hdr-compute-peak=`` Compute the HDR peak and frame average brightness per-frame instead of @@ -6413,8 +6431,8 @@ them. Apply desaturation for highlights (default: 0.75). The parameter controls the strength of the desaturation curve. A value of 0.0 completely disables it, while a value of 1.0 means that overly bright colors will tend towards - white. (This is not always the case, especially not for highlights that are - near primary colors) + white. This is not always the case, especially not for highlights that are + near primary colors. (``--vo=gpu`` only) Values in between apply progressively more/less aggressive desaturation. This setting helps prevent unnaturally oversaturated colors for diff --git a/meson.build b/meson.build index 407fd1ddea..a04fda3172 100644 --- a/meson.build +++ b/meson.build @@ -977,14 +977,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('>=170') + if pl_api_ver.version_compare('>=190') features += 'libplacebo-v4' libplacebo_v4 = true - message('libplacebo v4.170+ found! Enabling vo_gpu_next.') + message('libplacebo v4.190+ found! Enabling vo_gpu_next.') sources += files('video/out/vo_gpu_next.c', 'video/out/gpu_next/context.c') else - message('libplacebo v4.170+ not found! Disabling vo_gpu_next.') + message('libplacebo v4.190+ not found! Disabling vo_gpu_next.') endif endif diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index 841cf36db4..32049f584c 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -322,9 +322,10 @@ static const struct gl_video_opts gl_video_opts_def = { .background = {0, 0, 0, 255}, .gamma = 1.0f, .tone_map = { - .curve = TONE_MAPPING_BT_2390, + .curve = TONE_MAPPING_AUTO, .curve_param = NAN, .max_boost = 1.0, + .crosstalk = 0.04, .decay_rate = 100.0, .scene_threshold_low = 5.5, .scene_threshold_high = 10.0, @@ -378,13 +379,27 @@ const struct m_sub_options gl_video_conf = { {"target-peak", OPT_CHOICE(target_peak, {"auto", 0}), M_RANGE(10, 10000)}, {"tone-mapping", OPT_CHOICE(tone_map.curve, + {"auto", TONE_MAPPING_AUTO}, {"clip", TONE_MAPPING_CLIP}, {"mobius", TONE_MAPPING_MOBIUS}, {"reinhard", TONE_MAPPING_REINHARD}, {"hable", TONE_MAPPING_HABLE}, {"gamma", TONE_MAPPING_GAMMA}, {"linear", TONE_MAPPING_LINEAR}, - {"bt.2390", TONE_MAPPING_BT_2390})}, + {"spline", TONE_MAPPING_SPLINE}, + {"bt.2390", TONE_MAPPING_BT_2390}, + {"bt.2446a", TONE_MAPPING_BT_2446A})}, + {"tone-mapping-param", OPT_FLOATDEF(tone_map.curve_param)}, + {"inverse-tone-mapping", OPT_FLAG(tone_map.inverse)}, + {"tone-mapping-crosstalk", OPT_FLOAT(tone_map.crosstalk), + M_RANGE(0.0, 0.3)}, + {"tone-mapping-max-boost", OPT_FLOAT(tone_map.max_boost), + M_RANGE(1.0, 10.0)}, + {"tone-mapping-desaturate", OPT_FLOAT(tone_map.desat)}, + {"tone-mapping-desaturate-exponent", OPT_FLOAT(tone_map.desat_exp), + M_RANGE(0.0, 20.0)}, + {"gamut-warning", OPT_FLAG(tone_map.gamut_warning)}, + {"gamut-clipping", OPT_FLAG(tone_map.gamut_clipping)}, {"hdr-compute-peak", OPT_CHOICE(tone_map.compute_peak, {"auto", 0}, {"yes", 1}, @@ -395,14 +410,6 @@ const struct m_sub_options gl_video_conf = { M_RANGE(0, 20.0)}, {"hdr-scene-threshold-high", OPT_FLOAT(tone_map.scene_threshold_high), M_RANGE(0, 20.0)}, - {"tone-mapping-param", OPT_FLOATDEF(tone_map.curve_param)}, - {"tone-mapping-max-boost", OPT_FLOAT(tone_map.max_boost), - M_RANGE(1.0, 10.0)}, - {"tone-mapping-desaturate", OPT_FLOAT(tone_map.desat)}, - {"tone-mapping-desaturate-exponent", OPT_FLOAT(tone_map.desat_exp), - M_RANGE(0.0, 20.0)}, - {"gamut-warning", OPT_FLAG(tone_map.gamut_warning)}, - {"gamut-clipping", OPT_FLAG(tone_map.gamut_clipping)}, {"opengl-pbo", OPT_FLAG(pbo)}, SCALER_OPTS("scale", SCALER_SCALE), SCALER_OPTS("dscale", SCALER_DSCALE), @@ -2615,6 +2622,23 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, if (!src.sig_peak) src.sig_peak = mp_trc_nom_peak(src.gamma); + // Whitelist supported modes + switch (p->opts.tone_map.curve) { + case TONE_MAPPING_AUTO: + case TONE_MAPPING_CLIP: + case TONE_MAPPING_MOBIUS: + case TONE_MAPPING_REINHARD: + case TONE_MAPPING_HABLE: + case TONE_MAPPING_GAMMA: + case TONE_MAPPING_LINEAR: + case TONE_MAPPING_BT_2390: + break; + default: + MP_WARN(p, "Tone mapping curve unsupported by vo_gpu, falling back.\n"); + p->opts.tone_map.curve = TONE_MAPPING_AUTO; + break; + } + struct gl_tone_map_opts tone_map = p->opts.tone_map; bool detect_peak = tone_map.compute_peak >= 0 && mp_trc_is_hdr(src.gamma) && src.sig_peak > dst.sig_peak; diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h index dd16744778..13285bfce1 100644 --- a/video/out/gpu/video.h +++ b/video/out/gpu/video.h @@ -88,19 +88,24 @@ enum blend_subs_mode { }; enum tone_mapping { + TONE_MAPPING_AUTO, TONE_MAPPING_CLIP, TONE_MAPPING_MOBIUS, TONE_MAPPING_REINHARD, TONE_MAPPING_HABLE, TONE_MAPPING_GAMMA, TONE_MAPPING_LINEAR, + TONE_MAPPING_SPLINE, TONE_MAPPING_BT_2390, + TONE_MAPPING_BT_2446A, }; struct gl_tone_map_opts { int curve; float curve_param; float max_boost; + int inverse; + float crosstalk; int compute_peak; float decay_rate; float scene_threshold_low; diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index df379778fc..d7774a61e5 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -692,7 +692,8 @@ static void pass_tone_map(struct gl_shader_cache *sc, // This function always operates on an absolute scale, so ignore the // dst_peak normalization for it float dst_scale = dst_peak; - if (opts->curve == TONE_MAPPING_BT_2390) + enum tone_mapping curve = opts->curve ? opts->curve : TONE_MAPPING_BT_2390; + if (curve == TONE_MAPPING_BT_2390) dst_scale = 1.0; // Rescale the variables in order to bring it into a representation where @@ -709,7 +710,7 @@ static void pass_tone_map(struct gl_shader_cache *sc, GLSL(sig_peak *= slope;) float param = opts->curve_param; - switch (opts->curve) { + switch (curve) { case TONE_MAPPING_CLIP: GLSLF("sig = min(%f * sig, 1.0);\n", isnan(param) ? 1.0 : param); break; diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index fd4fd82b58..16ce51279a 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -1396,27 +1396,32 @@ static void update_render_options(struct priv *p) p->peak_detect.scene_threshold_low = opts->tone_map.scene_threshold_low; p->peak_detect.scene_threshold_high = opts->tone_map.scene_threshold_high; - static const enum pl_tone_mapping_algorithm tone_map_algos[] = { - [TONE_MAPPING_CLIP] = PL_TONE_MAPPING_CLIP, - [TONE_MAPPING_MOBIUS] = PL_TONE_MAPPING_MOBIUS, - [TONE_MAPPING_REINHARD] = PL_TONE_MAPPING_REINHARD, - [TONE_MAPPING_HABLE] = PL_TONE_MAPPING_HABLE, - [TONE_MAPPING_GAMMA] = PL_TONE_MAPPING_GAMMA, - [TONE_MAPPING_LINEAR] = PL_TONE_MAPPING_LINEAR, - [TONE_MAPPING_BT_2390] = PL_TONE_MAPPING_BT_2390, + static const struct pl_tone_map_function * const tone_map_funs[] = { + [TONE_MAPPING_AUTO] = &pl_tone_map_auto, + [TONE_MAPPING_CLIP] = &pl_tone_map_clip, + [TONE_MAPPING_MOBIUS] = &pl_tone_map_mobius, + [TONE_MAPPING_REINHARD] = &pl_tone_map_reinhard, + [TONE_MAPPING_HABLE] = &pl_tone_map_hable, + [TONE_MAPPING_GAMMA] = &pl_tone_map_gamma, + [TONE_MAPPING_LINEAR] = &pl_tone_map_linear, + [TONE_MAPPING_SPLINE] = &pl_tone_map_spline, + [TONE_MAPPING_BT_2390] = &pl_tone_map_bt2390, + [TONE_MAPPING_BT_2446A] = &pl_tone_map_bt2446a, }; p->color_map = pl_color_map_default_params; p->color_map.intent = opts->icc_opts->intent; - p->color_map.tone_mapping_algo = tone_map_algos[opts->tone_map.curve]; + p->color_map.tone_mapping_function = tone_map_funs[opts->tone_map.curve]; p->color_map.tone_mapping_param = opts->tone_map.curve_param; + p->color_map.inverse_tone_mapping = opts->tone_map.inverse; + p->color_map.tone_mapping_crosstalk = opts->tone_map.crosstalk; if (isnan(p->color_map.tone_mapping_param)) // vo_gpu compatibility p->color_map.tone_mapping_param = 0.0; - p->color_map.desaturation_strength = opts->tone_map.desat; - p->color_map.desaturation_exponent = opts->tone_map.desat_exp; - p->color_map.max_boost = opts->tone_map.max_boost; - p->color_map.gamut_warning = opts->tone_map.gamut_warning; - p->color_map.gamut_clipping = opts->tone_map.gamut_clipping; + if (opts->tone_map.gamut_clipping) { + p->color_map.gamut_mode = PL_GAMUT_DESATURATE; + } else if (opts->tone_map.gamut_warning) { + p->color_map.gamut_mode = PL_GAMUT_WARN; + } switch (opts->dither_algo) { case DITHER_ERROR_DIFFUSION: -- cgit v1.2.3