summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/video.c
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-02-13 15:33:00 +0100
committerwm4 <wm4@nowhere>2016-04-01 10:27:27 +0200
commit2dcf18c0c01282f0f0e72423038a78c1fc938b02 (patch)
tree2ca8bae135f1c29f6847e68861f8bb3461e8c8c1 /video/out/opengl/video.c
parent0d746522325923ff5926f3a3cd0024b679a8199f (diff)
downloadmpv-2dcf18c0c01282f0f0e72423038a78c1fc938b02.tar.bz2
mpv-2dcf18c0c01282f0f0e72423038a78c1fc938b02.tar.xz
vo_opengl: generate 3DLUT against source and use full BT.1886
This commit refactors the 3DLUT loading mechanism to build the 3DLUT against the original source characteristics of the file. This allows us, among other things, to use a real BT.1886 profile for the source. This also allows us to actually use perceptual mappings. Finally, this reduces errors on standard gamut displays (where the previous 3DLUT target of BT.2020 was unreasonably wide). This also improves the overall accuracy of the 3DLUT due to eliminating rounding errors where possible, and allows for more accurate use of LUT-based ICC profiles. The current code is somewhat more ugly than necessary, because the idea was to implement this commit in a working state first, and then maybe refactor the profile loading mechanism in a later commit. Fixes #2815.
Diffstat (limited to 'video/out/opengl/video.c')
-rw-r--r--video/out/opengl/video.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index e9bafc0d3f..c2d5fc211d 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -148,6 +148,7 @@ struct gl_video {
struct mpv_global *global;
struct mp_log *log;
struct gl_video_opts opts;
+ struct gl_lcms *cms;
bool gl_debug;
int texture_16bit_depth; // actual bits available in 16 bit textures
@@ -693,21 +694,31 @@ static void uninit_rendering(struct gl_video *p)
gl_video_reset_surfaces(p);
}
-void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d)
+void gl_video_update_profile(struct gl_video *p)
+{
+ if (p->use_lut_3d)
+ return;
+
+ p->use_lut_3d = true;
+ check_gl_features(p);
+
+ reinit_rendering(p);
+}
+
+static bool gl_video_get_lut3d(struct gl_video *p, enum mp_csp_prim prim,
+ enum mp_csp_trc trc)
{
GL *gl = p->gl;
- if (!lut3d) {
- if (p->use_lut_3d) {
- p->use_lut_3d = false;
- reinit_rendering(p);
- }
- return;
- }
+ if (!p->cms || !p->use_lut_3d)
+ return false;
- if (!(gl->mpgl_caps & MPGL_CAP_3D_TEX) || gl->es) {
- MP_ERR(p, "16 bit fixed point 3D textures not available.\n");
- return;
+ if (!gl_lcms_has_changed(p->cms, prim, trc))
+ return true;
+
+ struct lut3d *lut3d = NULL;
+ if (!gl_lcms_get_lut3d(p->cms, &lut3d, prim, trc) || !lut3d) {
+ return false;
}
if (!p->lut_3d_texture)
@@ -724,12 +735,9 @@ void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d)
gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
gl->ActiveTexture(GL_TEXTURE0);
- p->use_lut_3d = true;
- check_gl_features(p);
-
debug_check_gl(p, "after 3d lut creation");
- reinit_rendering(p);
+ return true;
}
// Fill an img_tex struct from an FBO + some metadata
@@ -1868,10 +1876,16 @@ static void pass_colormanage(struct gl_video *p, enum mp_csp_prim prim_src,
enum mp_csp_prim prim_dst = p->opts.target_prim;
if (p->use_lut_3d) {
- // The 3DLUT is hard-coded against BT.2020's gamut during creation, and
- // we never want to adjust its output (so treat it as linear)
- prim_dst = MP_CSP_PRIM_BT_2020;
- trc_dst = MP_CSP_TRC_LINEAR;
+ // The 3DLUT is always generated against the original source space
+ enum mp_csp_prim prim_orig = p->image_params.primaries;
+ enum mp_csp_trc trc_orig = p->image_params.gamma;
+
+ if (gl_video_get_lut3d(p, prim_orig, trc_orig)) {
+ prim_dst = prim_orig;
+ trc_dst = trc_orig;
+ } else {
+ p->use_lut_3d = false;
+ }
}
if (prim_dst == MP_CSP_PRIM_AUTO)
@@ -1885,10 +1899,10 @@ static void pass_colormanage(struct gl_video *p, enum mp_csp_prim prim_src,
trc_dst = MP_CSP_TRC_GAMMA22;
}
- bool need_cms = prim_src != prim_dst || p->use_lut_3d;
- bool need_gamma = trc_src != trc_dst || need_cms;
+ bool need_gamma = trc_src != trc_dst || prim_src != prim_dst;
if (need_gamma)
pass_linearize(p->sc, trc_src);
+
// Adapt to the right colorspace if necessary
if (prim_src != prim_dst) {
struct mp_csp_primaries csp_src = mp_get_csp_primaries(prim_src),
@@ -1898,16 +1912,14 @@ static void pass_colormanage(struct gl_video *p, enum mp_csp_prim prim_src,
gl_sc_uniform_mat3(p->sc, "cms_matrix", true, &m[0][0]);
GLSL(color.rgb = cms_matrix * color.rgb;)
}
+
+ if (need_gamma)
+ pass_delinearize(p->sc, trc_dst);
+
if (p->use_lut_3d) {
gl_sc_uniform_sampler(p->sc, "lut_3d", GL_TEXTURE_3D, TEXUNIT_3DLUT);
- // For the 3DLUT we are arbitrarily using 2.4 as input gamma to reduce
- // the severity of quantization errors.
- GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
- GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.4));)
GLSL(color.rgb = texture3D(lut_3d, color.rgb).rgb;)
}
- if (need_gamma)
- pass_delinearize(p->sc, trc_dst);
}
static void pass_dither(struct gl_video *p)
@@ -2681,7 +2693,7 @@ static void check_gl_features(struct gl_video *p)
// GLES3 doesn't provide filtered 16 bit integer textures
// GLES2 doesn't even provide 3D textures
- if (p->use_lut_3d && !(have_3d_tex && have_float_tex)) {
+ if (p->use_lut_3d && (!have_3d_tex || gl->es)) {
p->use_lut_3d = false;
MP_WARN(p, "Disabling color management (GLES unsupported).\n");
}
@@ -3001,7 +3013,8 @@ void gl_video_set_osd_source(struct gl_video *p, struct osd_state *osd)
recreate_osd(p);
}
-struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
+struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g,
+ struct gl_lcms *cms)
{
if (gl->version < 210 && gl->es < 200) {
mp_err(log, "At least OpenGL 2.1 or OpenGL ES 2.0 required.\n");
@@ -3013,6 +3026,7 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g)
.gl = gl,
.global = g,
.log = log,
+ .cms = cms,
.opts = gl_video_opts_def,
.gl_target = GL_TEXTURE_2D,
.texture_16bit_depth = 16,