summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--video/out/gpu/video_shaders.c51
1 files changed, 31 insertions, 20 deletions
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c
index cd63b37c11..d8a26542b0 100644
--- a/video/out/gpu/video_shaders.c
+++ b/video/out/gpu/video_shaders.c
@@ -494,8 +494,10 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
}
// Apply the OOTF mapping from a given light type to display-referred light.
-// Assumes absolute scale values.
-static void pass_ootf(struct gl_shader_cache *sc, enum mp_csp_light light)
+// Assumes absolute scale values. `peak` is used to tune the OOTF where
+// applicable (currently only HLG).
+static void pass_ootf(struct gl_shader_cache *sc, enum mp_csp_light light,
+ float peak)
{
if (light == MP_CSP_LIGHT_DISPLAY)
return;
@@ -504,12 +506,13 @@ static void pass_ootf(struct gl_shader_cache *sc, enum mp_csp_light light)
switch (light)
{
- case MP_CSP_LIGHT_SCENE_HLG:
- // HLG OOTF from BT.2100, assuming a reference display with a
- // peak of 1000 cd/m² -> gamma = 1.2
- GLSLF("color.rgb *= vec3(%f * pow(dot(src_luma, color.rgb), 0.2));\n",
- (1000 / MP_REF_WHITE) / pow(12, 1.2));
+ case MP_CSP_LIGHT_SCENE_HLG: {
+ // HLG OOTF from BT.2100, scaled to the chosen display peak
+ float gamma = MPMAX(1.0, 1.2 + 0.42 * log10(peak * MP_REF_WHITE / 1000.0));
+ GLSLF("color.rgb *= vec3(%f * pow(dot(src_luma, color.rgb), %f));\n",
+ peak / pow(12, gamma), gamma - 1.0);
break;
+ }
case MP_CSP_LIGHT_SCENE_709_1886:
// This OOTF is defined by encoding the result as 709 and then decoding
// it as 1886; although this is called 709_1886 we actually use the
@@ -528,7 +531,8 @@ static void pass_ootf(struct gl_shader_cache *sc, enum mp_csp_light light)
}
// Inverse of the function pass_ootf, for completeness' sake.
-static void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light light)
+static void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light light,
+ float peak)
{
if (light == MP_CSP_LIGHT_DISPLAY)
return;
@@ -537,10 +541,13 @@ static void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light ligh
switch (light)
{
- case MP_CSP_LIGHT_SCENE_HLG:
- GLSLF("color.rgb *= vec3(1.0/%f);\n", (1000 / MP_REF_WHITE) / pow(12, 1.2));
- GLSL(color.rgb /= vec3(max(1e-6, pow(dot(src_luma, color.rgb), 0.2/1.2)));)
+ case MP_CSP_LIGHT_SCENE_HLG: {
+ float gamma = MPMAX(1.0, 1.2 + 0.42 * log10(peak * MP_REF_WHITE / 1000.0));
+ GLSLF("color.rgb *= vec3(1.0/%f);\n", peak / pow(12, gamma));
+ GLSLF("color.rgb /= vec3(max(1e-6, pow(dot(src_luma, color.rgb), %f)));\n",
+ (gamma - 1.0) / gamma);
break;
+ }
case MP_CSP_LIGHT_SCENE_709_1886:
GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.4));)
GLSL(color.rgb = mix(color.rgb * vec3(1.0/4.5),
@@ -758,15 +765,19 @@ void pass_color_map(struct gl_shader_cache *sc,
mp_get_rgb2xyz_matrix(mp_get_csp_primaries(dst.primaries), rgb2xyz);
gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz[1]);
+ bool need_ootf = src.light != dst.light;
+ if (src.light == MP_CSP_LIGHT_SCENE_HLG && src.sig_peak != dst.sig_peak)
+ need_ootf = true;
+
// 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.sig_peak > dst.sig_peak ||
- src.light != dst.light;
+ bool need_linear = src.gamma != dst.gamma ||
+ src.primaries != dst.primaries ||
+ src.sig_peak > dst.sig_peak ||
+ need_ootf;
- if (need_gamma && !is_linear) {
+ if (need_linear && !is_linear) {
// We also pull it up so that 1.0 is the reference white
pass_linearize(sc, src.gamma);
is_linear = true;
@@ -775,8 +786,8 @@ void pass_color_map(struct gl_shader_cache *sc,
// Pre-scale the incoming values into an absolute scale
GLSLF("color.rgb *= vec3(%f);\n", mp_trc_nom_peak(src.gamma));
- if (src.light != dst.light)
- pass_ootf(sc, src.light);
+ if (need_ootf)
+ pass_ootf(sc, src.light, src.sig_peak);
// Adapt to the right colorspace if necessary
if (src.primaries != dst.primaries) {
@@ -798,8 +809,8 @@ void pass_color_map(struct gl_shader_cache *sc,
tone_mapping_param, tone_mapping_desat);
}
- if (src.light != dst.light)
- pass_inverse_ootf(sc, dst.light);
+ if (need_ootf)
+ pass_inverse_ootf(sc, dst.light, dst.sig_peak);
// Post-scale the outgoing values from absolute scale to normalized
GLSLF("color.rgb *= vec3(%f);\n", 1.0 / mp_trc_nom_peak(dst.gamma));