diff options
author | Niklas Haas <git@haasn.xyz> | 2018-02-03 14:45:01 +0100 |
---|---|---|
committer | Kevin Mitchell <kevmitch@gmail.com> | 2018-02-05 23:11:18 -0800 |
commit | e3d93fde2f60c3eef9673e73d7fe156f27ee715f (patch) | |
tree | 57c773ce0376cdaf38d164580fc1b230848248a0 /video/out/gpu/video.c | |
parent | 0870859e3d3658ae7cc69201cfc4bbe41d93fbf5 (diff) | |
download | mpv-e3d93fde2f60c3eef9673e73d7fe156f27ee715f.tar.bz2 mpv-e3d93fde2f60c3eef9673e73d7fe156f27ee715f.tar.xz |
vo_gpu: port HDR tone mapping algorithm from libplacebo
The current peak detection algorithm was very bugged (which contributed
to the excessive cross-frame flicker without long normalization) and
also didn't take into account the frame average brightness level.
The new algorithm both takes into account frame average brightness (in
addition to peak brightness), and also computes the values in a more
stable/correct way. (The old path was basically undefined behavior)
In addition to improving the algorithm, we also switch to hable tone
mapping by default, and try to enable peak computation automatically
whever possible (compute shaders + SSBOs supported). We also make the
desaturation milder, after extensive testing during libplacebo
development.
I also had to compensate a bit for the representational differences
between mpv and libplacebo (libplacebo treats 1.0 as the reference peak,
but mpv treats it as the nominal peak), but it shouldn't have caused any
problems.
This is still not quite the same as libplacebo, since libplacebo also
allows tagging the desired scene average brightness on the output, and
it also supports reading the scene average brightness from static
metadata (MaxFALL) where available. But those changes are a bit more
involved. It's possible we could also read this from metadata in the
future, but we have problems communicating with AVFrames as it is and I
don't want to touch the mpv colorimetry structs for the time being.
Diffstat (limited to 'video/out/gpu/video.c')
-rw-r--r-- | video/out/gpu/video.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index 24b14c537b..9bf7baeb77 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -313,9 +313,9 @@ static const struct gl_video_opts gl_video_opts_def = { .alpha_mode = ALPHA_BLEND_TILES, .background = {0, 0, 0, 255}, .gamma = 1.0f, - .tone_mapping = TONE_MAPPING_MOBIUS, + .tone_mapping = TONE_MAPPING_HABLE, .tone_mapping_param = NAN, - .tone_mapping_desat = 1.0, + .tone_mapping_desat = 0.5, .early_flush = -1, .hwdec_interop = "auto", }; @@ -358,7 +358,10 @@ const struct m_sub_options gl_video_conf = { {"hable", TONE_MAPPING_HABLE}, {"gamma", TONE_MAPPING_GAMMA}, {"linear", TONE_MAPPING_LINEAR})), - OPT_FLAG("hdr-compute-peak", compute_hdr_peak, 0), + OPT_CHOICE("hdr-compute-peak", compute_hdr_peak, 0, + ({"auto", 0}, + {"yes", 1}, + {"no", -1})), OPT_FLOAT("tone-mapping-param", tone_mapping_param, 0), OPT_FLOAT("tone-mapping-desaturate", tone_mapping_desat, 0), OPT_FLAG("gamut-warning", gamut_warning, 0), @@ -2442,20 +2445,18 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool dst.gamma = MP_CSP_TRC_GAMMA22; } - bool detect_peak = p->opts.compute_hdr_peak && mp_trc_is_hdr(src.gamma); + bool detect_peak = p->opts.compute_hdr_peak >= 0 && mp_trc_is_hdr(src.gamma); if (detect_peak && !p->hdr_peak_ssbo) { struct { - unsigned int sig_peak_raw; - unsigned int index; + unsigned int counter; + unsigned int frame_idx; + unsigned int frame_num; unsigned int frame_max[PEAK_DETECT_FRAMES+1]; + unsigned int frame_sum[PEAK_DETECT_FRAMES+1]; + unsigned int total_max; + unsigned int total_sum; } peak_ssbo = {0}; - // Prefill with safe values - int safe = MP_REF_WHITE * mp_trc_nom_peak(p->image_params.color.gamma); - peak_ssbo.sig_peak_raw = PEAK_DETECT_FRAMES * safe; - for (int i = 0; i < PEAK_DETECT_FRAMES+1; i++) - peak_ssbo.frame_max[i] = safe; - struct ra_buf_params params = { .type = RA_BUF_TYPE_SHADER_STORAGE, .size = sizeof(peak_ssbo), @@ -2465,7 +2466,8 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool p->hdr_peak_ssbo = ra_buf_create(ra, ¶ms); if (!p->hdr_peak_ssbo) { MP_WARN(p, "Failed to create HDR peak detection SSBO, disabling.\n"); - detect_peak = (p->opts.compute_hdr_peak = false); + detect_peak = false; + p->opts.compute_hdr_peak = -1; } } @@ -2473,9 +2475,15 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool pass_describe(p, "detect HDR peak"); pass_is_compute(p, 8, 8); // 8x8 is good for performance gl_sc_ssbo(p->sc, "PeakDetect", p->hdr_peak_ssbo, - "uint sig_peak_raw;" - "uint index;" - "uint frame_max[%d];", PEAK_DETECT_FRAMES + 1 + "uint counter;" + "uint frame_idx;" + "uint frame_num;" + "uint frame_max[%d];" + "uint frame_sum[%d];" + "uint total_max;" + "uint total_sum;", + PEAK_DETECT_FRAMES + 1, + PEAK_DETECT_FRAMES + 1 ); } @@ -3504,9 +3512,10 @@ static void check_gl_features(struct gl_video *p) p->opts.deband = 0; MP_WARN(p, "Disabling debanding (GLSL version too old).\n"); } - if ((!have_compute || !have_ssbo) && p->opts.compute_hdr_peak) { - p->opts.compute_hdr_peak = 0; - MP_WARN(p, "Disabling HDR peak computation (no compute shaders).\n"); + if ((!have_compute || !have_ssbo) && p->opts.compute_hdr_peak >= 0) { + int msgl = p->opts.compute_hdr_peak == 1 ? MSGL_WARN : MSGL_V; + MP_MSG(p, msgl, "Disabling HDR peak computation (no compute shaders).\n"); + p->opts.compute_hdr_peak = -1; } } |