diff options
author | Niklas Haas <git@nand.wakku.to> | 2014-06-22 08:33:43 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-06-22 19:02:06 +0200 |
commit | 17762a1919947db0e66e025bd2084de896eaa3fa (patch) | |
tree | 86aaf7c3c7bf37c9bf7a3c7f19eac9bacf7cd07e /video/out | |
parent | 204fed4d5b4aa20b5a6b5824f5d4e71ccbaf87fb (diff) | |
download | mpv-17762a1919947db0e66e025bd2084de896eaa3fa.tar.bz2 mpv-17762a1919947db0e66e025bd2084de896eaa3fa.tar.xz |
video: Generate an accurate CMS matrix instead of hard-coding
This also avoids an extra matrix multiplication when using :srgb, making
that path both more efficient and also eliminating more hard-coded
values.
In addition, the previously hard-coded XYZ to RGB matrix will be
dynamically generated.
Diffstat (limited to 'video/out')
-rw-r--r-- | video/out/gl_lcms.c | 14 | ||||
-rw-r--r-- | video/out/gl_video.c | 63 | ||||
-rw-r--r-- | video/out/gl_video_shaders.glsl | 31 |
3 files changed, 62 insertions, 46 deletions
diff --git a/video/out/gl_lcms.c b/video/out/gl_lcms.c index b1967ebf0e..b8416bea30 100644 --- a/video/out/gl_lcms.c +++ b/video/out/gl_lcms.c @@ -167,17 +167,19 @@ struct lut3d *mp_load_icc(struct mp_icc_opts *opts, struct mp_log *log, // We always generate the 3DLUT against BT.2020, and transform into this // space inside the shader if the source differs. - static const cmsCIExyY d65 = {0.3127, 0.3290, 1.0}; - static const cmsCIExyYTRIPLE bt2020prim = { - .Red = {0.708, 0.292, 1.0}, - .Green = {0.170, 0.797, 1.0}, - .Blue = {0.131, 0.046, 1.0}, + struct mp_csp_primaries csp = mp_get_csp_primaries(MP_CSP_PRIM_BT_2020); + + cmsCIExyY wp = {csp.white.x, csp.white.y, 1.0}; + cmsCIExyYTRIPLE prim = { + .Red = {csp.red.x, csp.red.y, 1.0}, + .Green = {csp.green.x, csp.green.y, 1.0}, + .Blue = {csp.blue.x, csp.blue.y, 1.0}, }; // 2.4 is arbitrarily used as a gamma compression factor for the 3DLUT, // reducing artifacts due to rounding errors on wide gamut profiles cmsToneCurve *tonecurve = cmsBuildGamma(cms, 2.4); - cmsHPROFILE vid_profile = cmsCreateRGBProfileTHR(cms, &d65, &bt2020prim, + cmsHPROFILE vid_profile = cmsCreateRGBProfileTHR(cms, &wp, &prim, (cmsToneCurve*[3]){tonecurve, tonecurve, tonecurve}); cmsFreeToneCurve(tonecurve); cmsHTRANSFORM trafo = cmsCreateTransformTHR(cms, vid_profile, TYPE_RGB_16, diff --git a/video/out/gl_video.c b/video/out/gl_video.c index f0981887c6..c2ed11be5c 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -195,6 +195,9 @@ struct gl_video { struct mp_csp_equalizer video_eq; struct mp_image_params image_params; + // Source and destination color spaces for the CMS matrix + struct mp_csp_primaries csp_src, csp_dest; + struct mp_rect src_rect; // displayed part of the source video struct mp_rect src_rect_rot;// compensated for optional rotation struct mp_rect dst_rect; // video rectangle on output window @@ -642,7 +645,7 @@ static void update_uniforms(struct gl_video *p, GLuint program) loc = gl->GetUniformLocation(program, "cms_matrix"); if (loc >= 0) { float cms_matrix[3][3] = {{0}}; - mp_get_cms_matrix(p->image_params.primaries, cms_matrix); + mp_get_cms_matrix(p->csp_src, p->csp_dest, cms_matrix); gl->UniformMatrix3fv(loc, 1, GL_TRUE, &cms_matrix[0][0]); } @@ -848,7 +851,43 @@ static void compile_shaders(struct gl_video *p) shader_prelude, PRELUDE_END); bool use_cms = p->opts.srgb || p->use_lut_3d; - bool use_cms_matrix = use_cms && (p->image_params.primaries != MP_CSP_PRIM_BT_2020); + + float input_gamma = 1.0; + float conv_gamma = 1.0; + + if (p->image_desc.flags & MP_IMGFLAG_XYZ) { + input_gamma *= 2.6; + + // If we're using cms, we can treat it as proper linear input, + // otherwise we just scale back to 1.95 as a reasonable approximation. + if (use_cms) { + p->is_linear_rgb = true; + } else { + conv_gamma *= 1.0 / 1.95; + } + } + + p->input_gamma = input_gamma; + p->conv_gamma = conv_gamma; + + bool use_input_gamma = p->input_gamma != 1.0; + bool use_conv_gamma = p->conv_gamma != 1.0; + bool use_const_luma = p->image_params.colorspace == MP_CSP_BT_2020_C; + + // 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; + + // Figure out the right color spaces we need to convert, if any + enum mp_csp_prim dest = p->opts.srgb ? MP_CSP_PRIM_BT_709 : MP_CSP_PRIM_BT_2020; + bool use_cms_matrix = false; + + if (use_cms && p->image_params.primaries != dest) { + p->csp_src = mp_get_csp_primaries(p->image_params.primaries); + p->csp_dest = mp_get_csp_primaries(dest); + use_cms_matrix = true; + } if (p->gl_target == GL_TEXTURE_RECTANGLE) { shader_def(&header, "VIDEO_SAMPLER", "sampler2DRect"); @@ -881,26 +920,6 @@ static void compile_shaders(struct gl_video *p) char *header_final = talloc_strdup(tmp, ""); char *header_sep = NULL; - float input_gamma = 1.0; - float conv_gamma = 1.0; - - if (p->image_desc.flags & MP_IMGFLAG_XYZ) { - input_gamma *= 2.6; - conv_gamma *= 1.0 / 2.2; - } - - p->input_gamma = input_gamma; - p->conv_gamma = conv_gamma; - - bool use_input_gamma = p->input_gamma != 1.0; - bool use_conv_gamma = p->conv_gamma != 1.0; - bool use_const_luma = p->image_params.colorspace == MP_CSP_BT_2020_C; - - // 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->image_format == IMGFMT_NV12 || p->image_format == IMGFMT_NV21) { shader_def(&header_conv, "USE_CONV", "CONV_NV12"); } else if (p->plane_count > 1) { diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl index 196e81e5e3..37834dc948 100644 --- a/video/out/gl_video_shaders.glsl +++ b/video/out/gl_video_shaders.glsl @@ -62,13 +62,6 @@ vec3 bt2020_compand(vec3 v) } #endif -// Constant matrix for conversion from BT.2020 to sRGB -const mat3 srgb_matrix = mat3( - 1.6604910, -0.1245505, -0.0181508, - -0.5876411, 1.1328999, -0.1005789, - -0.0728499, -0.0083494, 1.1187297 -); - #!section vertex_all #if __VERSION__ < 130 @@ -105,7 +98,9 @@ void main() { #endif #ifdef USE_OSD_CMS_MATRIX // Convert to the right target gamut first (to BT.709 for sRGB, - // and to BT.2020 for 3DLUT). + // and to BT.2020 for 3DLUT). Normal clamping here as perceptually + // accurate colorimetry is probably not worth the performance trade-off + // here. color.rgb = clamp(cms_matrix * color.rgb, 0, 1); #endif #ifdef USE_OSD_3DLUT @@ -113,7 +108,7 @@ void main() { color = vec4(texture3D(lut_3d, color.rgb).rgb, color.a); #endif #ifdef USE_OSD_SRGB - color.rgb = srgb_compand(clamp(srgb_matrix * color.rgb, 0, 1)); + color.rgb = srgb_compand(color.rgb); #endif texcoord = vertex_texcoord; @@ -452,24 +447,24 @@ void main() { // Convert to the right target gamut first (to BT.709 for sRGB, // and to BT.2020 for 3DLUT). color = cms_matrix * color; + + // Clamp to the target gamut. This clamp is needed because the gamma + // functions are not well-defined outside this range, which is related to + // the fact that they're not representable on the target device. + // TODO: Desaturate colorimetrically; this happens automatically for + // 3dlut targets but not for sRGB mode. Not sure if this is a requirement. + color = clamp(color, 0, 1); #endif #ifdef USE_3DLUT // For the 3DLUT we are arbitrarily using 2.4 as input gamma to reduce // the amount of rounding errors, so we pull up to that space first and // then pass it through the 3D texture. - // - // The value is clamped to [0,1] first because the gamma function is not - // well-defined outside it. This should not be a problem because the 3dlut - // is not defined for values outside its boundaries either way, and no - // media can possibly exceed its BT.2020 source gamut either way due to - // that being the biggest taggable color space. This is just to avoid - // numerical quirks like -1e-30 turning into NaN. - color = pow(clamp(color, 0, 1), vec3(1/2.4)); + color = pow(color, vec3(1/2.4)); color = texture3D(lut_3d, color).rgb; #endif #ifdef USE_SRGB // Adapt and compand from the linear BT2020 source to the sRGB output - color = srgb_compand(clamp(srgb_matrix * color, 0, 1)); + color = srgb_compand(color); #endif // If none of these options took care of companding again, we have to do // it manually here for the previously-expanded channels. This again |