mirror of https://github.com/mpv-player/mpv
vo_opengl: Linearize non-RGB sRGB files correctly (eg. JPEG)
Signed-off-by: wm4 <wm4@nowhere>
This commit is contained in:
parent
3803c14279
commit
863701391c
|
@ -67,6 +67,13 @@ enum mp_csp_prim {
|
|||
MP_CSP_PRIM_COUNT
|
||||
};
|
||||
|
||||
enum mp_csp_trc {
|
||||
MP_CSP_TRC_NONE,
|
||||
MP_CSP_TRC_BT_2020_APPROX,
|
||||
MP_CSP_TRC_BT_2020_EXACT,
|
||||
MP_CSP_TRC_SRGB
|
||||
};
|
||||
|
||||
// Any enum mp_csp_prim value is a valid index (except MP_CSP_PRIM_COUNT)
|
||||
extern const char *const mp_csp_prim_names[MP_CSP_PRIM_COUNT];
|
||||
|
||||
|
|
|
@ -901,11 +901,25 @@ static void compile_shaders(struct gl_video *p)
|
|||
bool use_conv_gamma = p->conv_gamma != 1.0;
|
||||
bool use_const_luma = p->image_params.colorspace == MP_CSP_BT_2020_C;
|
||||
|
||||
enum mp_csp_trc gamma_fun = MP_CSP_TRC_NONE;
|
||||
|
||||
// Linear light scaling is only enabled when either color correction
|
||||
// option (3dlut or srgb) is enabled, otherwise scaling is done in the
|
||||
// source space. We also need to linearize for constant luminance systems.
|
||||
bool convert_to_linear_gamma =
|
||||
(!p->is_linear_rgb && use_cms) || use_const_luma;
|
||||
if ((!p->is_linear_rgb && use_cms) || use_const_luma) {
|
||||
// We just use the color level range to distinguish between PC
|
||||
// content like images, which are most likely sRGB, and TV content
|
||||
// like movies, which are most likely BT.2020
|
||||
if (p->image_params.colorlevels == MP_CSP_LEVELS_PC && !p->hwdec_active) {
|
||||
// FIXME: I don't know if hwdec sets the color levels to PC or not,
|
||||
// but let's avoid the bug just in case.
|
||||
gamma_fun = MP_CSP_TRC_SRGB;
|
||||
} else if (p->opts.approx_gamma) {
|
||||
gamma_fun = MP_CSP_TRC_BT_2020_APPROX;
|
||||
} else {
|
||||
gamma_fun = MP_CSP_TRC_BT_2020_EXACT;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out the right color spaces we need to convert, if any
|
||||
enum mp_csp_prim prim_src = p->image_params.primaries, prim_dest;
|
||||
|
@ -944,9 +958,11 @@ static void compile_shaders(struct gl_video *p)
|
|||
|
||||
char *header_osd = talloc_strdup(tmp, header);
|
||||
shader_def_opt(&header_osd, "USE_OSD_LINEAR_CONV_APPROX",
|
||||
use_cms && p->opts.approx_gamma);
|
||||
use_cms && gamma_fun == MP_CSP_TRC_BT_2020_APPROX);
|
||||
shader_def_opt(&header_osd, "USE_OSD_LINEAR_CONV_BT2020",
|
||||
use_cms && !p->opts.approx_gamma);
|
||||
use_cms && gamma_fun == MP_CSP_TRC_BT_2020_EXACT);
|
||||
shader_def_opt(&header_osd, "USE_OSD_LINEAR_CONV_SRGB",
|
||||
use_cms && gamma_fun == MP_CSP_TRC_SRGB);
|
||||
shader_def_opt(&header_osd, "USE_OSD_CMS_MATRIX", use_cms_matrix);
|
||||
shader_def_opt(&header_osd, "USE_OSD_3DLUT", p->use_lut_3d);
|
||||
// 3DLUT overrides SRGB
|
||||
|
@ -981,9 +997,11 @@ static void compile_shaders(struct gl_video *p)
|
|||
shader_def_opt(&header_conv, "USE_CONV_GAMMA", use_conv_gamma);
|
||||
shader_def_opt(&header_conv, "USE_CONST_LUMA", use_const_luma);
|
||||
shader_def_opt(&header_conv, "USE_LINEAR_LIGHT_APPROX",
|
||||
convert_to_linear_gamma && p->opts.approx_gamma);
|
||||
gamma_fun == MP_CSP_TRC_BT_2020_APPROX);
|
||||
shader_def_opt(&header_conv, "USE_LINEAR_LIGHT_BT2020",
|
||||
convert_to_linear_gamma && !p->opts.approx_gamma);
|
||||
gamma_fun == MP_CSP_TRC_BT_2020_EXACT);
|
||||
shader_def_opt(&header_conv, "USE_LINEAR_LIGHT_SRGB",
|
||||
gamma_fun == MP_CSP_TRC_SRGB);
|
||||
if (p->opts.alpha_mode > 0 && p->has_alpha && p->plane_count > 3)
|
||||
shader_def(&header_conv, "USE_ALPHA_PLANE", "3");
|
||||
if (p->opts.alpha_mode == 2 && p->has_alpha)
|
||||
|
@ -1019,7 +1037,7 @@ static void compile_shaders(struct gl_video *p)
|
|||
|
||||
// Don't sample from input video textures before converting the input to
|
||||
// linear light.
|
||||
if (use_input_gamma || use_conv_gamma || convert_to_linear_gamma)
|
||||
if (use_input_gamma || use_conv_gamma || gamma_fun != MP_CSP_TRC_NONE)
|
||||
use_indirect = true;
|
||||
|
||||
// It doesn't make sense to scale the chroma with cscale in the 1. scale
|
||||
|
|
|
@ -43,6 +43,12 @@
|
|||
|
||||
// Earlier GLSL doesn't support mix() with bvec
|
||||
#if __VERSION__ >= 130
|
||||
vec3 srgb_expand(vec3 v)
|
||||
{
|
||||
return mix(v / 12.92, pow((v + vec3(0.055))/1.055, vec3(2.4)),
|
||||
lessThanEqual(vec3(0.04045), v));
|
||||
}
|
||||
|
||||
vec3 srgb_compand(vec3 v)
|
||||
{
|
||||
return mix(v * 12.92, 1.055 * pow(v, vec3(1.0/2.4)) - 0.055,
|
||||
|
@ -98,6 +104,9 @@ void main() {
|
|||
#ifdef USE_OSD_LINEAR_CONV_BT2020
|
||||
color.rgb = bt2020_expand(color.rgb);
|
||||
#endif
|
||||
#ifdef USE_OSD_LINEAR_CONV_SRGB
|
||||
color.rgb = srgb_expand(color.rgb);
|
||||
#endif
|
||||
#ifdef USE_OSD_CMS_MATRIX
|
||||
// Convert to the right target gamut first (to BT.709 for sRGB,
|
||||
// and to BT.2020 for 3DLUT). Normal clamping here as perceptually
|
||||
|
@ -439,6 +448,13 @@ void main() {
|
|||
// ... and actual BT.2020 (two-part function)
|
||||
color = bt2020_expand(color);
|
||||
#endif
|
||||
#ifdef USE_LINEAR_LIGHT_SRGB
|
||||
// This is not needed for most sRGB content since we can use GL_SRGB to
|
||||
// directly sample RGB texture in linear light, but for things which are
|
||||
// also sRGB but in a different format (such as JPEG's YUV), we need
|
||||
// to convert to linear light manually.
|
||||
color = srgb_expand(color);
|
||||
#endif
|
||||
#ifdef USE_CONST_LUMA
|
||||
// Calculate the green channel from the expanded RYcB
|
||||
// The BT.2020 specification says Yc = 0.2627*R + 0.6780*G + 0.0593*B
|
||||
|
|
Loading…
Reference in New Issue