summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-08-07 16:44:15 +0200
committerwm4 <wm4@nowhere>2017-08-07 16:44:15 +0200
commit346ac1e09f89bfbaac6329c89435e3c1faff6e8e (patch)
tree6288a19c964e27937043399b93c2fc94a5873628
parent46f7a4352e18b306d6cff7965c53150c5abcf20c (diff)
downloadmpv-346ac1e09f89bfbaac6329c89435e3c1faff6e8e.tar.bz2
mpv-346ac1e09f89bfbaac6329c89435e3c1faff6e8e.tar.xz
vo_opengl: simplify mirroring and fix it if glBlitFramebuffer is used
The vp_w/vp_h variables and parameters were not really used anymore (they were redundant with ra_tex w/h) - but vp_h was still used to identify whether rendering should be done mirrored. Simplify this by adding a fbodst struct (some bad naming), which contains the render target texture, and some parameters how it should be rendered to (for now only flipping). It would not be appropriate to make this a member of ra_tex, so it's a separate struct. Introduces a weird regression for the first frame rendered after interpolation is toggled at runtime, but seems to work otherwise. This is possibly due to the change that blit() now mirrors, instead of just copying. (This is also why ra_fns.blit is changed.) Fixes #4719.
-rw-r--r--video/out/opengl/osd.c8
-rw-r--r--video/out/opengl/osd.h4
-rw-r--r--video/out/opengl/ra.h12
-rw-r--r--video/out/opengl/ra_gl.c7
-rw-r--r--video/out/opengl/utils.c30
-rw-r--r--video/out/opengl/utils.h9
-rw-r--r--video/out/opengl/video.c71
7 files changed, 76 insertions, 65 deletions
diff --git a/video/out/opengl/osd.c b/video/out/opengl/osd.c
index a656451c2e..2678e12774 100644
--- a/video/out/opengl/osd.c
+++ b/video/out/opengl/osd.c
@@ -282,8 +282,8 @@ static void get_3d_side_by_side(int stereo_mode, int div[2])
}
}
-void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int vp_w, int vp_h, int index,
- struct gl_shader_cache *sc, struct ra_tex *target)
+void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int index,
+ struct gl_shader_cache *sc, struct fbodst target)
{
struct mpgl_osd_part *part = ctx->parts[index];
@@ -295,7 +295,7 @@ void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int vp_w, int vp_h, int index,
for (int x = 0; x < div[0]; x++) {
for (int y = 0; y < div[1]; y++) {
struct gl_transform t;
- gl_transform_ortho(&t, 0, vp_w, 0, vp_h);
+ gl_transform_ortho_fbodst(&t, target);
float a_x = ctx->osd_res.w * x;
float a_y = ctx->osd_res.h * y;
@@ -309,7 +309,7 @@ void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int vp_w, int vp_h, int index,
const int *factors = &blend_factors[part->format][0];
gl_sc_blend(sc, factors[0], factors[1], factors[2], factors[3]);
- gl_sc_dispatch_draw(sc, target, part->vertices, part->num_vertices);
+ gl_sc_dispatch_draw(sc, target.tex, part->vertices, part->num_vertices);
}
static void set_res(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode)
diff --git a/video/out/opengl/osd.h b/video/out/opengl/osd.h
index 08c143ac0e..9763d7e03a 100644
--- a/video/out/opengl/osd.h
+++ b/video/out/opengl/osd.h
@@ -17,8 +17,8 @@ void mpgl_osd_generate(struct mpgl_osd *ctx, struct mp_osd_res res, double pts,
void mpgl_osd_resize(struct mpgl_osd *ctx, struct mp_osd_res res, int stereo_mode);
bool mpgl_osd_draw_prepare(struct mpgl_osd *ctx, int index,
struct gl_shader_cache *sc);
-void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int vp_w, int vp_h, int index,
- struct gl_shader_cache *sc, struct ra_tex *target);
+void mpgl_osd_draw_finish(struct mpgl_osd *ctx, int index,
+ struct gl_shader_cache *sc, struct fbodst target);
int64_t mpgl_get_change_counter(struct mpgl_osd *ctx);
#endif
diff --git a/video/out/opengl/ra.h b/video/out/opengl/ra.h
index e93061eb61..cf18b110a5 100644
--- a/video/out/opengl/ra.h
+++ b/video/out/opengl/ra.h
@@ -349,17 +349,17 @@ struct ra_fns {
// Copy a sub-rectangle from one texture to another. The source/dest region
// is always within the texture bounds. Areas outside the dest region are
- // preserved. The formats of the textures will be losely compatible (this
- // probably has to be defined strictly). The dst texture can be a swapchain
- // framebuffer, but src can not. Only 2D textures are supported.
+ // preserved. The formats of the textures must be losely compatible. The
+ // dst texture can be a swapchain framebuffer, but src can not. Only 2D
+ // textures are supported.
// Both textures must have tex->params.render_dst==true (even src, which is
// an odd GL requirement).
- // A rectangle with negative width or height means a flipped copy should be
- // done. Coordinates are always in pixels.
+ // Rectangle with negative width/height lead to flipping, different src/dst
+ // sizes lead to point scaling. Coordinates are always in pixels.
// Optional. Only available if RA_CAP_BLIT is set (if it's not set, the must
// not be called, even if it's non-NULL).
void (*blit)(struct ra *ra, struct ra_tex *dst, struct ra_tex *src,
- int dst_x, int dst_y, struct mp_rect *src_rc);
+ struct mp_rect *dst_rc, struct mp_rect *src_rc);
// Compile a shader and create a pipeline. This is a rare operation.
// The params pointer and anything it points to must stay valid until
diff --git a/video/out/opengl/ra_gl.c b/video/out/opengl/ra_gl.c
index 3966afcebb..bc38a60e53 100644
--- a/video/out/opengl/ra_gl.c
+++ b/video/out/opengl/ra_gl.c
@@ -498,7 +498,7 @@ static void gl_clear(struct ra *ra, struct ra_tex *dst, float color[4],
}
static void gl_blit(struct ra *ra, struct ra_tex *dst, struct ra_tex *src,
- int dst_x, int dst_y, struct mp_rect *src_rc)
+ struct mp_rect *dst_rc, struct mp_rect *src_rc)
{
GL *gl = ra_gl_get(ra);
@@ -508,13 +508,10 @@ static void gl_blit(struct ra *ra, struct ra_tex *dst, struct ra_tex *src,
struct ra_tex_gl *src_gl = src->priv;
struct ra_tex_gl *dst_gl = dst->priv;
- int w = mp_rect_w(*src_rc);
- int h = mp_rect_h(*src_rc);
-
gl->BindFramebuffer(GL_READ_FRAMEBUFFER, src_gl->fbo);
gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_gl->fbo);
gl->BlitFramebuffer(src_rc->x0, src_rc->y0, src_rc->x1, src_rc->y1,
- dst_x, dst_y, dst_x + w, dst_y + h,
+ dst_rc->x0, dst_rc->y0, dst_rc->x1, dst_rc->y1,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
gl->BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
diff --git a/video/out/opengl/utils.c b/video/out/opengl/utils.c
index ffc2fb3fce..a0174e8063 100644
--- a/video/out/opengl/utils.c
+++ b/video/out/opengl/utils.c
@@ -33,6 +33,12 @@ void gl_transform_trans(struct gl_transform t, struct gl_transform *x)
gl_transform_vec(t, &x->t[0], &x->t[1]);
}
+void gl_transform_ortho_fbodst(struct gl_transform *t, struct fbodst fbo)
+{
+ int y_dir = fbo.flip ? -1 : 1;
+ gl_transform_ortho(t, 0, fbo.tex->params.w, 0, fbo.tex->params.h * y_dir);
+}
+
// Create a texture and a FBO using the texture as color attachments.
// fmt: texture internal format
// If the parameters are the same as the previous call, do not touch it.
@@ -41,6 +47,8 @@ void gl_transform_trans(struct gl_transform t, struct gl_transform *x)
bool fbotex_change(struct fbotex *fbo, struct ra *ra, struct mp_log *log,
int w, int h, const struct ra_format *fmt, int flags)
{
+ int lw = w, lh = h;
+
if (fbo->tex) {
int cw = w, ch = h;
int rw = fbo->tex->params.w, rh = fbo->tex->params.h;
@@ -50,15 +58,10 @@ bool fbotex_change(struct fbotex *fbo, struct ra *ra, struct mp_log *log,
if ((flags & FBOTEX_FUZZY_H) && ch < rh)
ch = rh;
- if (rw == cw && rh == ch && fbo->tex->params.format == fmt) {
- fbo->lw = w;
- fbo->lh = h;
- return true;
- }
+ if (rw == cw && rh == ch && fbo->tex->params.format == fmt)
+ goto done;
}
- int lw = w, lh = h;
-
if (flags & FBOTEX_FUZZY_W)
w = MP_ALIGN_UP(w, 256);
if (flags & FBOTEX_FUZZY_H)
@@ -75,10 +78,6 @@ bool fbotex_change(struct fbotex *fbo, struct ra *ra, struct mp_log *log,
*fbo = (struct fbotex) {
.ra = ra,
- .rw = w,
- .rh = h,
- .lw = lw,
- .lh = lh,
};
struct ra_tex_params params = {
@@ -100,6 +99,15 @@ bool fbotex_change(struct fbotex *fbo, struct ra *ra, struct mp_log *log,
return false;
}
+done:
+
+ fbo->lw = lw;
+ fbo->lh = lh;
+
+ fbo->fbo = (struct fbodst){
+ .tex = fbo->tex,
+ };
+
return true;
}
diff --git a/video/out/opengl/utils.h b/video/out/opengl/utils.h
index 12d77efbf8..5f6efc9299 100644
--- a/video/out/opengl/utils.h
+++ b/video/out/opengl/utils.h
@@ -62,11 +62,18 @@ static inline bool gl_transform_eq(struct gl_transform a, struct gl_transform b)
void gl_transform_trans(struct gl_transform t, struct gl_transform *x);
+struct fbodst {
+ struct ra_tex *tex;
+ bool flip; // mirror vertically
+};
+
+void gl_transform_ortho_fbodst(struct gl_transform *t, struct fbodst fbo);
+
struct fbotex {
struct ra *ra;
struct ra_tex *tex;
- int rw, rh; // real (texture) size, same as tex->params.w/h
int lw, lh; // logical (configured) size, <= than texture size
+ struct fbodst fbo;
};
void fbotex_uninit(struct fbotex *fbo);
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 6300ea84ea..57c1c5b18f 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -1162,14 +1162,14 @@ static void dispatch_compute(struct gl_video *p, int w, int h,
p->pass_tex_num = 0;
}
-static struct mp_pass_perf render_pass_quad(struct gl_video *p, int vp_w, int vp_h,
- struct ra_tex *target,
+static struct mp_pass_perf render_pass_quad(struct gl_video *p,
+ struct fbodst target,
const struct mp_rect *dst)
{
struct vertex va[6] = {0};
struct gl_transform t;
- gl_transform_ortho(&t, 0, vp_w, 0, vp_h);
+ gl_transform_ortho_fbodst(&t, target);
float x[2] = {dst->x0, dst->x1};
float y[2] = {dst->y0, dst->y1};
@@ -1197,15 +1197,15 @@ static struct mp_pass_perf render_pass_quad(struct gl_video *p, int vp_w, int vp
va[4] = va[2];
va[5] = va[1];
- return gl_sc_dispatch_draw(p->sc, target, va, 6);
+ return gl_sc_dispatch_draw(p->sc, target.tex, va, 6);
}
-static void finish_pass_direct(struct gl_video *p, struct ra_tex *target,
- int vp_w, int vp_h, const struct mp_rect *dst)
+static void finish_pass_direct(struct gl_video *p, struct fbodst target,
+ const struct mp_rect *dst)
{
pass_prepare_src_tex(p);
gl_sc_set_vertex_format(p->sc, vertex_vao, sizeof(struct vertex));
- pass_record(p, render_pass_quad(p, vp_w, vp_h, target, dst));
+ pass_record(p, render_pass_quad(p, target, dst));
debug_check_gl(p, "after rendering");
memset(&p->pass_tex, 0, sizeof(p->pass_tex));
p->pass_tex_num = 0;
@@ -1234,8 +1234,7 @@ static void finish_pass_fbo(struct gl_video *p, struct fbotex *dst_fbo,
debug_check_gl(p, "after dispatching compute shader");
} else {
- finish_pass_direct(p, dst_fbo->tex, dst_fbo->rw, dst_fbo->rh,
- &(struct mp_rect){0, 0, w, h});
+ finish_pass_direct(p, dst_fbo->fbo, &(struct mp_rect){0, 0, w, h});
}
}
@@ -2607,8 +2606,7 @@ static void pass_dither(struct gl_video *p)
// Draws the OSD, in scene-referred colors.. If cms is true, subtitles are
// instead adapted to the display's gamut.
static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts,
- struct mp_osd_res rect, int vp_w, int vp_h,
- struct ra_tex *target, bool cms)
+ struct mp_osd_res rect, struct fbodst target, bool cms)
{
mpgl_osd_generate(p->osd, rect, pts, p->image_params.stereo_out, draw_flags);
@@ -2628,7 +2626,7 @@ static void pass_draw_osd(struct gl_video *p, int draw_flags, double pts,
pass_colormanage(p, csp_srgb, true);
}
- mpgl_osd_draw_finish(p->osd, vp_w, vp_h, n, p->sc, target);
+ mpgl_osd_draw_finish(p->osd, n, p->sc, target);
}
timer_pool_stop(p->osd_timer);
@@ -2719,7 +2717,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
};
finish_pass_fbo(p, &p->blend_subs_fbo, rect.w, rect.h, 0);
pass_draw_osd(p, OSD_DRAW_SUB_ONLY, vpts, rect,
- rect.w, rect.h, p->blend_subs_fbo.tex, false);
+ p->blend_subs_fbo.fbo, false);
pass_read_fbo(p, &p->blend_subs_fbo);
pass_describe(p, "blend subs video");
}
@@ -2749,8 +2747,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
}
finish_pass_fbo(p, &p->blend_subs_fbo, p->texture_w, p->texture_h, 0);
pass_draw_osd(p, OSD_DRAW_SUB_ONLY, vpts, rect,
- p->texture_w, p->texture_h, p->blend_subs_fbo.tex,
- false);
+ p->blend_subs_fbo.fbo, false);
pass_read_fbo(p, &p->blend_subs_fbo);
pass_describe(p, "blend subs");
}
@@ -2760,7 +2757,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi, uint64_t
return true;
}
-static void pass_draw_to_screen(struct gl_video *p, struct ra_tex *fbo)
+static void pass_draw_to_screen(struct gl_video *p, struct fbodst fbo)
{
if (p->dumb_mode)
pass_render_frame_dumb(p);
@@ -2805,7 +2802,7 @@ static void pass_draw_to_screen(struct gl_video *p, struct ra_tex *fbo)
pass_dither(p);
pass_describe(p, "output to screen");
- finish_pass_direct(p, fbo, p->vp_w, p->vp_h, &p->dst_rect);
+ finish_pass_direct(p, fbo, &p->dst_rect);
}
static bool update_fbosurface(struct gl_video *p, struct mp_image *mpi,
@@ -2834,7 +2831,7 @@ static bool update_fbosurface(struct gl_video *p, struct mp_image *mpi,
// Draws an interpolate frame to fbo, based on the frame timing in t
static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
- struct ra_tex *fbo)
+ struct fbodst fbo)
{
bool is_new = false;
@@ -3025,8 +3022,10 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
}
}
- struct ra_tex *target =
- ra_create_wrapped_fb(p->ra, fbo, p->vp_w, abs(p->vp_h));
+ struct fbodst target = {
+ .tex = ra_create_wrapped_fb(p->ra, fbo, p->vp_w, abs(p->vp_h)),
+ .flip = p->vp_h < 0,
+ };
struct mp_rect target_rc = {0, 0, p->vp_w, abs(p->vp_h)};
p->broken_frame = false;
@@ -3038,13 +3037,13 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
{
struct m_color c = p->opts.background;
float color[4] = {c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0};
- p->ra->fns->clear(p->ra, target, color, &target_rc);
+ p->ra->fns->clear(p->ra, target.tex, color, &target_rc);
}
if (p->hwdec_active && p->hwdec->driver->overlay_frame) {
if (has_frame) {
float *color = p->hwdec->overlay_colorkey;
- p->ra->fns->clear(p->ra, target, color, &p->dst_rect);
+ p->ra->fns->clear(p->ra, target.tex, color, &p->dst_rect);
}
if (frame->frame_id != p->image.id || !frame->current)
@@ -3084,14 +3083,14 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
// For the non-interpolation case, we draw to a single "cache"
// FBO to speed up subsequent re-draws (if any exist)
- struct ra_tex *dest_fbo = target;
+ struct fbodst dest_fbo = target;
if (frame->num_vsyncs > 1 && frame->display_synced &&
!p->dumb_mode && (p->ra->caps & RA_CAP_BLIT))
{
fbotex_change(&p->output_fbo, p->ra, p->log,
- p->vp_w, abs(p->vp_h),
+ target.tex->params.w, target.tex->params.h,
p->fbo_format, FBOTEX_FUZZY);
- dest_fbo = p->output_fbo.tex;
+ dest_fbo = p->output_fbo.fbo;
p->output_fbo_valid = true;
}
pass_draw_to_screen(p, dest_fbo);
@@ -3101,14 +3100,15 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, int fbo)
if (p->output_fbo_valid) {
pass_info_reset(p, true);
pass_describe(p, "redraw cached frame");
- struct mp_rect rc = p->dst_rect;
- if (p->vp_h < 0) {
- rc.y1 = -p->vp_h - p->dst_rect.y0;
- rc.y0 = -p->vp_h - p->dst_rect.y1;
+ struct mp_rect src = p->dst_rect;
+ struct mp_rect dst = src;
+ if (target.flip) {
+ dst.y0 = target.tex->params.h - src.y0;
+ dst.y1 = target.tex->params.h - src.y1;
}
timer_pool_start(p->blit_timer);
- p->ra->fns->blit(p->ra, target, p->output_fbo.tex,
- rc.x0, rc.y0, &rc);
+ p->ra->fns->blit(p->ra, target.tex, p->output_fbo.tex,
+ &dst, &src);
timer_pool_stop(p->blit_timer);
pass_record(p, timer_pool_measure(p->blit_timer));
}
@@ -3129,7 +3129,7 @@ done:
pass_info_reset(p, true);
pass_draw_osd(p, p->opts.blend_subs ? OSD_DRAW_OSD_ONLY : 0,
- p->osd_pts, p->osd_rect, p->vp_w, p->vp_h, target, true);
+ p->osd_pts, p->osd_rect, target, true);
debug_check_gl(p, "after OSD rendering");
}
@@ -3137,10 +3137,10 @@ done:
// Make the screen solid blue to make it visually clear that an
// error has occurred
float color[4] = {0.0, 0.05, 0.5, 1.0};
- p->ra->fns->clear(p->ra, target, color, &target_rc);
+ p->ra->fns->clear(p->ra, target.tex, color, &target_rc);
}
- ra_tex_free(p->ra, &target);
+ ra_tex_free(p->ra, &target.tex);
// The playloop calls this last before waiting some time until it decides
// to call flip_page(). Tell OpenGL to start execution of the GPU commands
@@ -3228,8 +3228,7 @@ static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame,
fbotex_change(fbo, p->ra, p->log, w, h * 2, fmt, 0);
pass_describe(p, "vdpau reinterleaving");
- finish_pass_direct(p, fbo->tex, fbo->rw, fbo->rh,
- &(struct mp_rect){0, 0, w, h * 2});
+ finish_pass_direct(p, fbo->fbo, &(struct mp_rect){0, 0, w, h * 2});
for (int t = 0; t < 2; t++)
ra_tex_free(p->ra, &tmp[t]);