summaryrefslogtreecommitdiffstats
path: root/video/out/gpu
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2020-07-19 08:04:49 +0200
committerNiklas Haas <git@haasn.xyz>2020-07-19 08:07:48 +0200
commitc53a47eda38e1724a7c731c8bbf0b5015fcb7135 (patch)
treedf0cf06796e8483c119e2ec7a5aed30213ba7fe7 /video/out/gpu
parent96cdf5315e1bbda580c68976fb6e763c4c43729d (diff)
downloadmpv-c53a47eda38e1724a7c731c8bbf0b5015fcb7135.tar.bz2
mpv-c53a47eda38e1724a7c731c8bbf0b5015fcb7135.tar.xz
vo_gpu: clip highlights before tone-mapping
Rather than after tone-mapping. This prevents overflow when the pre-tonemapped signal contains inputs exceeding sig_peak. I also realized that with this clipping in place, post-clipping no longer needs to be done, so this isn't even particularly slower. The only two exceptions to the rule are "clip" and "linear", which relied on the post-clipping to do their tone mapping properly. Fixes #7929
Diffstat (limited to 'video/out/gpu')
-rw-r--r--video/out/gpu/video_shaders.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c
index 19b002170d..a85b02ddee 100644
--- a/video/out/gpu/video_shaders.c
+++ b/video/out/gpu/video_shaders.c
@@ -679,7 +679,9 @@ static void pass_tone_map(struct gl_shader_cache *sc,
if (opts->compute_peak >= 0)
hdr_update_peak(sc, opts);
- GLSLF("vec3 sig = color.rgb;\n");
+ // Always hard-clip the upper bound of the signal range to avoid functions
+ // exploding on inputs greater than 1.0
+ GLSLF("vec3 sig = min(color.rgb, sig_peak);\n");
// This function always operates on an absolute scale, so ignore the
// dst_peak normalization for it
@@ -703,7 +705,7 @@ static void pass_tone_map(struct gl_shader_cache *sc,
float param = opts->curve_param;
switch (opts->curve) {
case TONE_MAPPING_CLIP:
- GLSLF("sig = %f * sig;\n", isnan(param) ? 1.0 : param);
+ GLSLF("sig = min(%f * sig, 1.0);\n", isnan(param) ? 1.0 : param);
break;
case TONE_MAPPING_MOBIUS:
@@ -755,7 +757,7 @@ static void pass_tone_map(struct gl_shader_cache *sc,
case TONE_MAPPING_LINEAR: {
float coeff = isnan(param) ? 1.0 : param;
- GLSLF("sig = %f / sig_peak * sig;\n", coeff);
+ GLSLF("sig = min(%f / sig_peak, 1.0) * sig;\n", coeff);
break;
}
@@ -797,7 +799,6 @@ static void pass_tone_map(struct gl_shader_cache *sc,
abort();
}
- GLSL(sig = min(sig, vec3(1.0));)
GLSL(vec3 sig_lin = color.rgb * (sig[sig_idx] / sig_orig);)
// Mix between the per-channel tone mapped and the linear tone mapped