summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/video_shaders.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/opengl/video_shaders.c')
-rw-r--r--video/out/opengl/video_shaders.c57
1 files changed, 51 insertions, 6 deletions
diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c
index 7b736f1d5d..eded7d59c2 100644
--- a/video/out/opengl/video_shaders.c
+++ b/video/out/opengl/video_shaders.c
@@ -361,9 +361,11 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
}
// Tone map from a known peak brightness to the range [0,1]
-void pass_tone_map(struct gl_shader_cache *sc, float peak,
- enum tone_mapping algo, float param)
+static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
+ enum tone_mapping algo, float param)
{
+ GLSLF("// HDR tone mapping\n");
+
switch (algo) {
case TONE_MAPPING_CLIP:
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
@@ -373,7 +375,7 @@ void pass_tone_map(struct gl_shader_cache *sc, float peak,
float contrast = isnan(param) ? 0.5 : param,
offset = (1.0 - contrast) / contrast;
GLSLF("color.rgb = color.rgb / (color.rgb + vec3(%f));\n", offset);
- GLSLF("color.rgb *= vec3(%f);\n", (peak + offset) / peak);
+ GLSLF("color.rgb *= vec3(%f);\n", (ref_peak + offset) / ref_peak);
break;
}
@@ -384,20 +386,20 @@ void pass_tone_map(struct gl_shader_cache *sc, float peak,
A, C*B, D*E, A, B, D*F, E/F);
GLSLHF("}\n");
- GLSLF("color.rgb = hable(color.rgb) / hable(vec3(%f));\n", peak);
+ GLSLF("color.rgb = hable(color.rgb) / hable(vec3(%f));\n", ref_peak);
break;
}
case TONE_MAPPING_GAMMA: {
float gamma = isnan(param) ? 1.8 : param;
GLSLF("color.rgb = pow(color.rgb / vec3(%f), vec3(%f));\n",
- peak, 1.0/gamma);
+ ref_peak, 1.0/gamma);
break;
}
case TONE_MAPPING_LINEAR: {
float coeff = isnan(param) ? 1.0 : param;
- GLSLF("color.rgb = vec3(%f) * color.rgb;\n", coeff / peak);
+ GLSLF("color.rgb = vec3(%f) * color.rgb;\n", coeff / ref_peak);
break;
}
@@ -406,6 +408,49 @@ void pass_tone_map(struct gl_shader_cache *sc, float peak,
}
}
+// Map colors from one source space to another. These source spaces
+// must be known (i.e. not MP_CSP_*_AUTO), as this function won't perform
+// any auto-guessing.
+void pass_color_map(struct gl_shader_cache *sc,
+ struct mp_colorspace src, struct mp_colorspace dst,
+ enum tone_mapping algo, float tone_mapping_param)
+{
+ GLSLF("// color mapping\n");
+
+ // All operations from here on require linear light as a starting point,
+ // so we linearize even if src.gamma == dst.gamma when one of the other
+ // operations needs it
+ bool need_gamma = src.gamma != dst.gamma ||
+ src.primaries != dst.primaries ||
+ src.nom_peak != dst.nom_peak ||
+ src.sig_peak > dst.nom_peak;
+
+ if (need_gamma)
+ pass_linearize(sc, src.gamma);
+
+ // Stretch the signal value to renormalize to the dst nominal peak
+ if (src.nom_peak != dst.nom_peak)
+ GLSLF("color.rgb *= vec3(%f);\n", src.nom_peak / dst.nom_peak);
+
+ // Tone map to prevent clipping when the source signal peak exceeds the
+ // encodable range.
+ if (src.sig_peak > dst.nom_peak)
+ pass_tone_map(sc, src.sig_peak / dst.nom_peak, algo, tone_mapping_param);
+
+ // Adapt to the right colorspace if necessary
+ if (src.primaries != dst.primaries) {
+ struct mp_csp_primaries csp_src = mp_get_csp_primaries(src.primaries),
+ csp_dst = mp_get_csp_primaries(dst.primaries);
+ float m[3][3] = {{0}};
+ mp_get_cms_matrix(csp_src, csp_dst, MP_INTENT_RELATIVE_COLORIMETRIC, m);
+ gl_sc_uniform_mat3(sc, "cms_matrix", true, &m[0][0]);
+ GLSL(color.rgb = cms_matrix * color.rgb;)
+ }
+
+ if (need_gamma)
+ pass_delinearize(sc, dst.gamma);
+}
+
// Wide usage friendly PRNG, shamelessly stolen from a GLSL tricks forum post.
// Obtain random numbers by calling rand(h), followed by h = permute(h) to
// update the state. Assumes the texture was hooked.