summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-14 23:16:58 +0200
committerwm4 <wm4@nowhere>2013-06-15 18:34:43 +0200
commit18b6ff0d4ed6c053f1bb2751bc837c0e642ff726 (patch)
treeedfe28e3876f0c7df751e14f342e73154f36d0ca /video
parentabbb45ce13bdf9c21ad673253ca5cc6279bbe36d (diff)
downloadmpv-18b6ff0d4ed6c053f1bb2751bc837c0e642ff726.tar.bz2
mpv-18b6ff0d4ed6c053f1bb2751bc837c0e642ff726.tar.xz
gl_video: fix scaling when image is cropped, or with no-npot
When the displayed image is cropped in Y direction (like using panscan controls when playing 4:3 video on a 16:9 monitor), and separated scaling is used, the texture size for the FBO holding the intermediate result was calculated incorrectly. This could lead to artifacts, which were quite apparent with extreme scale factors. Actually, the size of that texture is OK, but the texture shouldn't be used to hold the complete scaled image. Instead, it should be used for the visible part of the image only. Because separate scaling works by scaling in Y direction first, it's still fine to scale the image on the full image width on the first pass. This helps avoiding artifacts on the left/right border of the image when scaling in X direction, as the scaler will try to fetch pixels from beyond the border. (The left border is still kind of fine, but the right border will fetch garbage, unless the texture is strictly sized, or explicit clamping is added to the shader. Too much trouble, so using the full image width is simpler.) Also fix some issues with no-npot mode, which enables use of power-of-2 textures. Maybe this mode isn't really useful anymore (modern hardware is faster with smaller non-power-of-2 textures), but keep it for now.
Diffstat (limited to 'video')
-rw-r--r--video/out/gl_video.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 25b1547327..1f140b040d 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -132,7 +132,7 @@ struct fbotex {
GLuint fbo;
GLuint texture;
int tex_w, tex_h; // size of .texture
- int vp_w, vp_h; // viewport of fbo / used part of the texture
+ int vp_x, vp_y, vp_w, vp_h; // viewport of fbo / used part of the texture
};
struct gl_video {
@@ -397,10 +397,12 @@ static bool fbotex_init(struct gl_video *p, struct fbotex *fbo, int w, int h,
assert(!fbo->fbo);
assert(!fbo->texture);
- tex_size(p, w, h, &fbo->tex_w, &fbo->tex_h);
+ *fbo = (struct fbotex) {
+ .vp_w = w,
+ .vp_h = h,
+ };
- fbo->vp_w = w;
- fbo->vp_h = h;
+ tex_size(p, w, h, &fbo->tex_w, &fbo->tex_h);
mp_msg(MSGT_VO, MSGL_V, "[gl] Create FBO: %dx%d\n", fbo->tex_w, fbo->tex_h);
@@ -505,7 +507,7 @@ static void update_uniforms(struct gl_video *p, GLuint program)
gl->Uniform1i(gl->GetUniformLocation(program, textures_n), n);
gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n),
- p->image.planes[n].w, p->image.planes[n].h);
+ p->image.planes[n].tex_w, p->image.planes[n].tex_h);
}
gl->Uniform2f(gl->GetUniformLocation(program, "dither_size"),
@@ -1055,7 +1057,7 @@ static void reinit_rendering(struct gl_video *p)
update_all_uniforms(p);
if (p->indirect_program && !p->indirect_fbo.fbo)
- fbotex_init(p, &p->indirect_fbo, p->texture_w, p->texture_h,
+ fbotex_init(p, &p->indirect_fbo, p->image_w, p->image_h,
p->opts.fbo_format);
recreate_osd(p);
@@ -1214,17 +1216,17 @@ static void change_dither_trafo(struct gl_video *p)
gl->UseProgram(0);
}
-static void render_to_fbo(struct gl_video *p, struct fbotex *fbo, int w, int h,
- int tex_w, int tex_h)
+static void render_to_fbo(struct gl_video *p, struct fbotex *fbo,
+ int x, int y, int w, int h, int tex_w, int tex_h)
{
GL *gl = p->gl;
- gl->Viewport(0, 0, fbo->vp_w, fbo->vp_h);
+ gl->Viewport(fbo->vp_x, fbo->vp_y, fbo->vp_w, fbo->vp_h);
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo);
struct vertex vb[VERTICES_PER_QUAD];
write_quad(vb, -1, -1, 1, 1,
- 0, 0, w, h,
+ x, y, x + w, y + h,
tex_w, tex_h,
NULL, false);
draw_triangles(p, vb, VERTICES_PER_QUAD);
@@ -1244,7 +1246,8 @@ static void handle_pass(struct gl_video *p, struct fbotex **source,
gl->BindTexture(GL_TEXTURE_2D, (*source)->texture);
gl->UseProgram(program);
- render_to_fbo(p, fbo, (*source)->vp_w, (*source)->vp_h,
+ render_to_fbo(p, fbo, (*source)->vp_x, (*source)->vp_y,
+ (*source)->vp_w, (*source)->vp_h,
(*source)->tex_w, (*source)->tex_h);
*source = fbo;
}
@@ -1272,23 +1275,37 @@ void gl_video_render_frame(struct gl_video *p)
set_image_textures(p, vimg);
struct fbotex dummy = {
- .vp_w = p->image_w, .vp_h = p->image_h,
- .tex_w = p->texture_w, .tex_h = p->texture_h,
+ .vp_w = p->image_w,
+ .vp_h = p->image_h,
+ .tex_w = p->texture_w,
+ .tex_h = p->texture_h,
.texture = vimg->planes[0].gl_texture,
};
struct fbotex *source = &dummy;
handle_pass(p, &source, &p->indirect_fbo, p->indirect_program);
+
+ // Clip to visible height so that separate scaling scales the visible part
+ // only (and the target FBO texture can have a bounded size).
+ // Don't clamp width; too hard to get correct final scaling on l/r borders.
+ dummy = *source;
+ source = &dummy;
+ source->vp_y = p->src_rect.y0,
+ source->vp_h = p->src_rect.y1 - p->src_rect.y0,
+
handle_pass(p, &source, &p->scale_sep_fbo, p->scale_sep_program);
gl->BindTexture(GL_TEXTURE_2D, source->texture);
gl->UseProgram(p->final_program);
- float final_texw = p->image_w * source->tex_w / (float)source->vp_w;
- float final_texh = p->image_h * source->tex_h / (float)source->vp_h;
+ float final_texw = source->tex_w;
+ float final_texh = source->tex_h;
+
+ struct mp_rect src = {p->src_rect.x0, source->vp_y,
+ p->src_rect.x1, source->vp_y + source->vp_h};
if (p->opts.stereo_mode) {
- int w = p->src_rect.x1 - p->src_rect.x0;
+ int w = src.x1 - src.x0;
int imgw = p->image_w;
glEnable3DLeft(gl, p->opts.stereo_mode);
@@ -1296,8 +1313,8 @@ void gl_video_render_frame(struct gl_video *p)
write_quad(vb,
p->dst_rect.x0, p->dst_rect.y0,
p->dst_rect.x1, p->dst_rect.y1,
- p->src_rect.x0 / 2, p->src_rect.y0,
- p->src_rect.x0 / 2 + w / 2, p->src_rect.y1,
+ src.x0 / 2, src.y0,
+ src.x0 / 2 + w / 2, src.y1,
final_texw, final_texh,
NULL, is_flipped);
draw_triangles(p, vb, VERTICES_PER_QUAD);
@@ -1307,8 +1324,8 @@ void gl_video_render_frame(struct gl_video *p)
write_quad(vb,
p->dst_rect.x0, p->dst_rect.y0,
p->dst_rect.x1, p->dst_rect.y1,
- p->src_rect.x0 / 2 + imgw / 2, p->src_rect.y0,
- p->src_rect.x0 / 2 + imgw / 2 + w / 2, p->src_rect.y1,
+ src.x0 / 2 + imgw / 2, src.y0,
+ src.x0 / 2 + imgw / 2 + w / 2, src.y1,
final_texw, final_texh,
NULL, is_flipped);
draw_triangles(p, vb, VERTICES_PER_QUAD);
@@ -1318,8 +1335,8 @@ void gl_video_render_frame(struct gl_video *p)
write_quad(vb,
p->dst_rect.x0, p->dst_rect.y0,
p->dst_rect.x1, p->dst_rect.y1,
- p->src_rect.x0, p->src_rect.y0,
- p->src_rect.x1, p->src_rect.y1,
+ src.x0, src.y0,
+ src.x1, src.y1,
final_texw, final_texh,
NULL, is_flipped);
draw_triangles(p, vb, VERTICES_PER_QUAD);