summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2014-06-22 08:33:43 +0200
committerwm4 <wm4@nowhere>2014-06-22 19:02:06 +0200
commit17762a1919947db0e66e025bd2084de896eaa3fa (patch)
tree86aaf7c3c7bf37c9bf7a3c7f19eac9bacf7cd07e /video/out
parent204fed4d5b4aa20b5a6b5824f5d4e71ccbaf87fb (diff)
downloadmpv-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.c14
-rw-r--r--video/out/gl_video.c63
-rw-r--r--video/out/gl_video_shaders.glsl31
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