summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2015-03-15 22:52:34 +0100
committerwm4 <wm4@nowhere>2015-03-16 09:29:47 +0100
commitce2da9cfcf23ea5170d026670fc0e87892818b6c (patch)
tree7c4b4f8db646c2f1b68d7faded74bd13f83343e4
parent41f9b9376b561a592b60cf30047ff1da98389faf (diff)
downloadmpv-ce2da9cfcf23ea5170d026670fc0e87892818b6c.tar.bz2
mpv-ce2da9cfcf23ea5170d026670fc0e87892818b6c.tar.xz
vo_opengl: color manage after interpolation
This moves the color management code out of pass_render_main (which is now dedicated solely to up/downscaling and hence renamed pass_scale_main) and into a new function, which gets called from pass_draw_to_screen instead. This makes more sense from a logical standpoint, and also means that we interpolate in linear RGB, before color management - rather than after it, which is significantly better for color accuracy and probably also interpolation quality.
-rw-r--r--video/out/gl_video.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 17dd121709..ec15f4ce62 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -204,6 +204,7 @@ struct gl_video {
// temporary during rendering
struct src_tex pass_tex[TEXUNIT_VIDEO_NUM];
bool use_indirect;
+ bool use_linear;
int frames_rendered;
@@ -1423,9 +1424,8 @@ static void get_scale_factors(struct gl_video *p, double xy[2])
(double)(p->src_rect.y1 - p->src_rect.y0);
}
-// Takes care of the main scaling and post-conversions such as gamut/gamma
-// mapping or color management.
-static void pass_render_main(struct gl_video *p)
+// Takes care of the main scaling and pre/post-conversions
+static void pass_scale_main(struct gl_video *p)
{
// Figure out the main scaler.
double xy[2];
@@ -1452,9 +1452,9 @@ static void pass_render_main(struct gl_video *p)
// Pre-conversion, like linear light/sigmoidization
GLSLF("// scaler pre-conversion\n");
- bool use_linear = p->opts.linear_scaling || p->opts.sigmoid_upscaling
+ p->use_linear = p->opts.linear_scaling || p->opts.sigmoid_upscaling
|| use_cms || p->image_params.gamma == MP_CSP_TRC_LINEAR;
- if (use_linear) {
+ if (p->use_linear) {
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
p->use_indirect = true;
switch (p->image_params.gamma) {
@@ -1473,7 +1473,7 @@ static void pass_render_main(struct gl_video *p)
}
}
- bool use_sigmoid = use_linear && p->opts.sigmoid_upscaling && upscaling;
+ bool use_sigmoid = p->use_linear && p->opts.sigmoid_upscaling && upscaling;
float sig_center, sig_slope, sig_offset, sig_scale;
if (use_sigmoid) {
p->use_indirect = true;
@@ -1532,7 +1532,11 @@ static void pass_render_main(struct gl_video *p)
GLSLF("color.rgb = (1.0/(1.0 + exp(%f * (%f - color.rgb))) - %f) / %f;\n",
sig_slope, sig_center, sig_offset, sig_scale);
}
+}
+// Adapts the colors to the display device's native gamut.
+static void pass_colormanage(struct gl_video *p)
+{
GLSLF("// color management\n");
enum mp_csp_trc trc_dst = p->opts.target_trc;
enum mp_csp_prim prim_src = p->image_params.primaries,
@@ -1575,7 +1579,7 @@ static void pass_render_main(struct gl_video *p)
// Don't perform any gamut mapping unless linear light input is present to
// begin with
- if (use_linear && trc_dst != MP_CSP_TRC_LINEAR) {
+ if (p->use_linear && trc_dst != MP_CSP_TRC_LINEAR) {
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
switch (trc_dst) {
case MP_CSP_TRC_SRGB:
@@ -1697,17 +1701,18 @@ static void pass_dither(struct gl_video *p)
}
// The main rendering function, takes care of everything up to and including
-// color management
-static void pass_draw_frame(struct gl_video *p)
+// upscaling
+static void pass_render_frame(struct gl_video *p)
{
p->use_indirect = false; // set to true as needed by pass_*
pass_read_video(p);
pass_convert_yuv(p);
- pass_render_main(p);
+ pass_scale_main(p);
}
static void pass_draw_to_screen(struct gl_video *p, int fbo)
{
+ pass_colormanage(p);
pass_dither(p);
int flags = (p->image_params.rotate % 90 ? 0 : p->image_params.rotate / 90)
| (p->image.image_flipped ? 4 : 0);
@@ -1725,7 +1730,7 @@ static void gl_video_interpolate_frame(struct gl_video *p, int fbo,
// First of all, figure out if we have a frame availble at all, and draw
// it manually + reset the queue if not
if (!p->surfaces[p->surface_now].pts) {
- pass_draw_frame(p);
+ pass_render_frame(p);
finish_pass_fbo(p, &p->surfaces[p->surface_now].fbotex,
vp_w, vp_h, 0, fuzz);
p->surfaces[p->surface_now].pts = t ? t->pts : 0;
@@ -1760,7 +1765,7 @@ static void gl_video_interpolate_frame(struct gl_video *p, int fbo,
if (t && surface_dst != surface_bse &&
p->surfaces[p->surface_idx].pts < t->pts) {
MP_STATS(p, "new-pts");
- pass_draw_frame(p);
+ pass_render_frame(p);
finish_pass_fbo(p, &p->surfaces[surface_dst].fbotex,
vp_w, vp_h, 0, fuzz);
p->surfaces[surface_dst].pts = t->pts;
@@ -1855,7 +1860,7 @@ void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t)
gl_video_interpolate_frame(p, fbo, t);
} else {
// Skip interpolation if there's nothing to be done
- pass_draw_frame(p);
+ pass_render_frame(p);
pass_draw_to_screen(p, fbo);
}