From f3fccfc395ddb7a504ab2aae48452178fa92d907 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Mon, 3 Jan 2022 04:31:50 +0100 Subject: vo_gpu: add --gamut-mapping-mode Merge --gamut-clipping and --gamut-warning into a single option, --gamut-mapping-mode, better corresponding to the new vo_gpu_next APIs and allowing us to easily extend this option as new modes are added in the future. --- DOCS/interface-changes.rst | 1 + DOCS/man/options.rst | 37 ++++++++++++++++++------------------- video/out/gpu/video.c | 23 ++++++++++++++++++++--- video/out/gpu/video.h | 11 +++++++++-- video/out/gpu/video_shaders.c | 6 +++--- video/out/vo_gpu_next.c | 14 +++++++++----- 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 2c59f0f6b5..75516627df 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -35,6 +35,7 @@ Interface changes - add `--tone-mapping-crosstalk` - add `--tone-mapping` options `auto`, `spline` and `bt.2446a` - add `--inverse-tone-mapping` + - add `--gamut-mapping-mode`, replacing `--gamut-clipping` and `--gamut-warning` --- 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 6742ec1a6c..bd2b9be470 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6385,6 +6385,24 @@ them. it too high will make dark scenes appear unnaturally bright. (``-vo=gpu`` only) +``--gamut-mapping-mode`` + Specifies the algorithm used for reducing the gamut of images for the + target display, after any tone mapping is done. + + auto + Choose the best mode automatically. (Default) + clip + Hard-clip to the gamut (per-channel). + warn + Simply highlight out-of-gamut pixels. + desaturate + Chromatically desaturate out-of-gamut colors towards white. + darken + Linearly darken the entire image, then clip to the color volume. Unlike + ``clip``, this does not destroy detail in saturated regions, but comes + at the cost of sometimes significantly lowering output brightness. + (``--vo=gpu-next`` only) + ``--hdr-compute-peak=`` Compute the HDR peak and frame average brightness per-frame instead of relying on tagged metadata. These values are averaged over local regions as @@ -6448,25 +6466,6 @@ them. desaturated. The default of 1.5 provides a reasonable balance. Decreasing this exponent makes the curve more aggressive. -``--gamut-warning`` - If enabled, mpv will mark all clipped/out-of-gamut pixels that exceed a - given threshold (currently hard-coded to 101%). The affected pixels will be - inverted to make them stand out. Note: This option applies after the - effects of all of mpv's color space transformation / tone mapping options, - so it's a good idea to combine this with ``--tone-mapping=clip`` and use - ``--target-prim`` to set the gamut to simulate. For example, - ``--target-prim=bt.709`` would make mpv highlight all pixels that exceed the - gamut of a standard gamut (sRGB) display. This option also does not work - well with ICC profiles, since the 3DLUTs are always generated against the - source color space and have chromatically-accurate clipping built in. - -``--gamut-clipping`` - If enabled (default: yes), mpv will colorimetrically clip out-of-gamut - colors by desaturating them (preserving luma), rather than hard-clipping - each component individually. This should make playback of wide gamut - content on typical (standard gamut) monitors look much more aesthetically - pleasing and less blown-out. - ``--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 32049f584c..8236a7b43f 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -331,7 +331,6 @@ static const struct gl_video_opts gl_video_opts_def = { .scene_threshold_high = 10.0, .desat = 0.75, .desat_exp = 1.5, - .gamut_clipping = 1, }, .early_flush = -1, .hwdec_interop = "auto", @@ -398,8 +397,12 @@ const struct m_sub_options gl_video_conf = { {"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)}, + {"gamut-mapping-mode", OPT_CHOICE(tone_map.gamut_mode, + {"auto", GAMUT_AUTO}, + {"clip", GAMUT_CLIP}, + {"warn", GAMUT_WARN}, + {"desaturate", GAMUT_DESATURATE}, + {"darken", GAMUT_DARKEN})}, {"hdr-compute-peak", OPT_CHOICE(tone_map.compute_peak, {"auto", 0}, {"yes", 1}, @@ -474,6 +477,8 @@ const struct m_sub_options gl_video_conf = { {"opengl-gamma", OPT_REPLACED("gamma-factor")}, {"linear-scaling", OPT_REMOVED("Split into --linear-upscaling and " "--linear-downscaling")}, + {"gamut-warning", OPT_REMOVED("Replaced by --gamut-mapping-mode=warn")}, + {"gamut-clipping", OPT_REMOVED("Replaced by --gamut-mapping-mode=desaturate")}, {0} }, .size = sizeof(struct gl_video_opts), @@ -2639,6 +2644,18 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, break; } + switch (p->opts.tone_map.gamut_mode) { + case GAMUT_AUTO: + case GAMUT_WARN: + case GAMUT_CLIP: + case GAMUT_DESATURATE: + break; + default: + MP_WARN(p, "Gamut mapping mode unsupported by vo_gpu, falling back.\n"); + p->opts.tone_map.gamut_mode = GAMUT_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 13285bfce1..adeadaba65 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 gamut_mode { + GAMUT_AUTO, + GAMUT_CLIP, + GAMUT_WARN, + GAMUT_DESATURATE, + GAMUT_DARKEN, +}; + struct gl_tone_map_opts { int curve; float curve_param; @@ -112,8 +120,7 @@ struct gl_tone_map_opts { float scene_threshold_high; float desat; float desat_exp; - int gamut_warning; // bool - int gamut_clipping; // bool + int gamut_mode; }; struct gl_video_opts { diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index d7774a61e5..6dcef77fa0 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -882,7 +882,7 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, gl_sc_uniform_mat3(sc, "cms_matrix", true, &m[0][0]); GLSL(color.rgb = cms_matrix * color.rgb;) - if (opts->gamut_clipping) { + if (!opts->gamut_mode || opts->gamut_mode == GAMUT_DESATURATE) { GLSL(float cmin = min(min(color.r, color.g), color.b);) GLSL(if (cmin < 0.0) { float luma = dot(dst_luma, color.rgb); @@ -907,8 +907,8 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, GLSLF("color.rgb *= vec3(%f);\n", 1.0 / dst_range); - // Warn for remaining out-of-gamut colors is enabled - if (opts->gamut_warning) { + // Warn for remaining out-of-gamut colors if enabled + if (opts->gamut_mode == GAMUT_WARN) { GLSL(if (any(greaterThan(color.rgb, vec3(1.005))) || any(lessThan(color.rgb, vec3(-0.005))))) GLSL(color.rgb = vec3(1.0) - color.rgb;) // invert diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 14e2fdeadc..390852ff71 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -1399,6 +1399,13 @@ static void update_render_options(struct priv *p) [TONE_MAPPING_BT_2446A] = &pl_tone_map_bt2446a, }; + static const enum pl_gamut_mode gamut_modes[] = { + [GAMUT_CLIP] = PL_GAMUT_CLIP, + [GAMUT_WARN] = PL_GAMUT_WARN, + [GAMUT_DESATURATE] = PL_GAMUT_DESATURATE, + [GAMUT_DARKEN] = PL_GAMUT_DARKEN, + }; + 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]; @@ -1407,11 +1414,8 @@ static void update_render_options(struct priv *p) 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; - 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; - } + if (opts->tone_map.gamut_mode != GAMUT_AUTO) + p->color_map.gamut_mode = gamut_modes[opts->tone_map.gamut_mode]; switch (opts->dither_algo) { case DITHER_ERROR_DIFFUSION: -- cgit v1.2.3