From d09c73c7b2b0135cb24ab2173b3c4ee1c55840b0 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Tue, 4 Jan 2022 01:50:00 +0100 Subject: vo_gpu: add --tone-mapping-mode This merges the old desaturation control options into a single enumeration, with the goal of both simplifying how these options work and also making this list more extensible (including, notably, new options only supported by vo_gpu_next). For the hybrid option, I decided to port the (slightly tweaked) values from libplacebo's pre-refactor defaults, rather than the old values we had in mpv, to more visually match the look of the vo_gpu_next hybrid. --- DOCS/interface-changes.rst | 2 ++ DOCS/man/options.rst | 43 ++++++++++++++++++++++--------------------- video/out/gpu/video.c | 25 ++++++++++++++++++++----- video/out/gpu/video.h | 11 +++++++++-- video/out/gpu/video_shaders.c | 30 ++++++++++++++++++------------ video/out/vo_gpu_next.c | 9 +++++++++ 6 files changed, 80 insertions(+), 40 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 75516627df..48c5b62881 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -36,6 +36,8 @@ Interface changes - add `--tone-mapping` options `auto`, `spline` and `bt.2446a` - add `--inverse-tone-mapping` - add `--gamut-mapping-mode`, replacing `--gamut-clipping` and `--gamut-warning` + - add `--tone-mapping-mode`, replacing `--tone-mapping-desaturate` and + `--tone-mapping-desaturate-exponent`. --- 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 bd2b9be470..7b51b585e8 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6385,6 +6385,28 @@ them. it too high will make dark scenes appear unnaturally bright. (``-vo=gpu`` only) +``--tone-mapping-mode`` + Controls how the tone mapping function is applied to colors. + + auto + Choose the best mode automatically. (Default) + rgb + Tone-map per-channel (RGB). Has a tendency to severely distort colors, + desaturate highlights, and is generally not very recommended. However, + this is the mode used in many displays and TVs (especially early ones), + and so sometimes it's needed to reproduce the artistic intent a film + was mastered with. + max + Tone-map on the brightest component in the video. Has a tendency to + lead to weirdly oversaturated colors, and loss of dark details. + hybrid + A hybrid approach that uses linear tone-mapping for midtones and + per-channel tone mapping for highlights. + luma + Luminance-based method from ITU-R BT.2446a, including fixed gamut + reductions to account for brightness-related perceptual nonuniformity. + (``--vo=gpu-next`` only) + ``--gamut-mapping-mode`` Specifies the algorithm used for reducing the gamut of images for the target display, after any tone mapping is done. @@ -6445,27 +6467,6 @@ them. aggressive, up to the limit of the high threshold (at which point the filter becomes instant). -``--tone-mapping-desaturate=<0.0..1.0>`` - 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. (``--vo=gpu`` only) - - Values in between apply progressively more/less aggressive desaturation. - This setting helps prevent unnaturally oversaturated colors for - super-highlights, by (smoothly) turning them into less saturated (per - channel tone mapped) colors instead. This makes images feel more natural, - at the cost of chromatic distortions for out-of-range colors. The default - value of 0.75 provides a good balance. Setting this to 0.0 preserves the - chromatic accuracy of the tone mapping process. - -``--tone-mapping-desaturate-exponent=<0.0..20.0>`` - This setting controls the exponent of the desaturation curve, which - controls how bright a color needs to be in order to start being - desaturated. The default of 1.5 provides a reasonable balance. Decreasing - this exponent makes the curve more aggressive. - ``--use-embedded-icc-profile`` Load the embedded ICC profile contained in media files such as PNG images. (Default: yes). Note that this option only works when also using a display diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index 8236a7b43f..d0d0509792 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -329,8 +329,6 @@ static const struct gl_video_opts gl_video_opts_def = { .decay_rate = 100.0, .scene_threshold_low = 5.5, .scene_threshold_high = 10.0, - .desat = 0.75, - .desat_exp = 1.5, }, .early_flush = -1, .hwdec_interop = "auto", @@ -394,9 +392,12 @@ const struct m_sub_options gl_video_conf = { 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)}, + {"tone-mapping-mode", OPT_CHOICE(tone_map.mode, + {"auto", TONE_MAP_MODE_AUTO}, + {"rgb", TONE_MAP_MODE_RGB}, + {"max", TONE_MAP_MODE_MAX}, + {"hybrid", TONE_MAP_MODE_HYBRID}, + {"luma", TONE_MAP_MODE_LUMA})}, {"gamut-mapping-mode", OPT_CHOICE(tone_map.gamut_mode, {"auto", GAMUT_AUTO}, {"clip", GAMUT_CLIP}, @@ -479,6 +480,8 @@ const struct m_sub_options gl_video_conf = { "--linear-downscaling")}, {"gamut-warning", OPT_REMOVED("Replaced by --gamut-mapping-mode=warn")}, {"gamut-clipping", OPT_REMOVED("Replaced by --gamut-mapping-mode=desaturate")}, + {"tone-mapping-desaturate", OPT_REMOVED("Replaced by --tone-mapping-mode")}, + {"tone-mapping-desaturate-exponent", OPT_REMOVED("Replaced by --tone-mapping-mode")}, {0} }, .size = sizeof(struct gl_video_opts), @@ -2644,6 +2647,18 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, break; } + switch (p->opts.tone_map.mode) { + case TONE_MAP_MODE_AUTO: + case TONE_MAP_MODE_RGB: + case TONE_MAP_MODE_MAX: + case TONE_MAP_MODE_HYBRID: + break; + default: + MP_WARN(p, "Tone mapping mode unsupported by vo_gpu, falling back.\n"); + p->opts.tone_map.mode = TONE_MAP_MODE_AUTO; + break; + } + switch (p->opts.tone_map.gamut_mode) { case GAMUT_AUTO: case GAMUT_WARN: diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h index adeadaba65..0bb180e514 100644 --- a/video/out/gpu/video.h +++ b/video/out/gpu/video.h @@ -100,6 +100,14 @@ enum tone_mapping { TONE_MAPPING_BT_2446A, }; +enum tone_mapping_mode { + TONE_MAP_MODE_AUTO, + TONE_MAP_MODE_RGB, + TONE_MAP_MODE_MAX, + TONE_MAP_MODE_HYBRID, + TONE_MAP_MODE_LUMA, +}; + enum gamut_mode { GAMUT_AUTO, GAMUT_CLIP, @@ -114,12 +122,11 @@ struct gl_tone_map_opts { float max_boost; int inverse; float crosstalk; + int mode; int compute_peak; float decay_rate; float scene_threshold_low; float scene_threshold_high; - float desat; - float desat_exp; int gamut_mode; }; diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index 6dcef77fa0..9628274b19 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -809,18 +809,24 @@ static void pass_tone_map(struct gl_shader_cache *sc, abort(); } - GLSL(vec3 sig_lin = color.rgb * (sig[sig_idx] / sig_orig);) - - // Mix between the per-channel tone mapped and the linear tone mapped - // signal based on the desaturation strength - if (opts->desat > 0) { - float base = 0.18 * dst_scale; - GLSLF("float coeff = max(sig[sig_idx] - %f, 1e-6) / " - " max(sig[sig_idx], 1.0);\n", base); - GLSLF("coeff = %f * pow(coeff, %f);\n", opts->desat, opts->desat_exp); - GLSLF("color.rgb = mix(sig_lin, %f * sig, coeff);\n", dst_scale); - } else { - GLSL(color.rgb = sig_lin;) + switch (opts->mode) { + case TONE_MAP_MODE_RGB: + GLSL(color.rgb = sig;) + break; + case TONE_MAP_MODE_MAX: + GLSL(color.rgb *= sig[sig_idx] / sig_orig;) + break; + case TONE_MAP_MODE_AUTO: + case TONE_MAP_MODE_HYBRID: + GLSLF("float coeff = max(sig[sig_idx] - %f, 1e-6) / \n" + " max(sig[sig_idx], 1.0); \n" + "coeff = %f * pow(coeff / %f, %f); \n" + "color.rgb *= sig[sig_idx] / sig_orig; \n" + "color.rgb = mix(color.rgb, %f * sig, coeff); \n", + 0.18 / dst_scale, 0.90, dst_scale, 0.20, dst_scale); + break; + default: + abort(); } } diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 390852ff71..9bbb58101f 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -1406,12 +1406,21 @@ static void update_render_options(struct priv *p) [GAMUT_DARKEN] = PL_GAMUT_DARKEN, }; + static const enum pl_tone_map_mode tone_map_modes[] = { + [TONE_MAP_MODE_AUTO] = PL_TONE_MAP_AUTO, + [TONE_MAP_MODE_RGB] = PL_TONE_MAP_RGB, + [TONE_MAP_MODE_MAX] = PL_TONE_MAP_MAX, + [TONE_MAP_MODE_HYBRID] = PL_TONE_MAP_HYBRID, + [TONE_MAP_MODE_LUMA] = PL_TONE_MAP_LUMA, + }; + p->color_map = pl_color_map_default_params; p->color_map.intent = opts->icc_opts->intent; 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; + p->color_map.tone_mapping_mode = tone_map_modes[opts->tone_map.mode]; if (isnan(p->color_map.tone_mapping_param)) // vo_gpu compatibility p->color_map.tone_mapping_param = 0.0; if (opts->tone_map.gamut_mode != GAMUT_AUTO) -- cgit v1.2.3