vo_opengl: fix alpha values written to the framebuffer

When blending OSD and subtitles onto the video, we write bogus alpha
values. This doesn't normally matter, because these values are normally
unused and discarded. But at least on Wayland, the alpha values are used
by the compositor and leads to transparent windows even with opaque
video on places where the OSD happens to use transparency.

(Also see github issue #338.)

Until now, the alpha basically contained garbage. The source factor
GL_SRC_ALPHA meant that alpha was multiplied with itself. Use GL_ONE
instead (which is why we have to use glBlendFuncSeparate()). This should
give correct results, even with video that has alpha. (Or at least it's
something close to correct, I haven't thought too hard how the
compositor will blend it, and in fact I couldn't manage to test it.)

If glBlendFuncSeparate() is not available, fall back to glBlendFunc(),
which does the same as the code did before this commit. Technically, we
support GL 1.1, but glBlendFuncSeparate is 1.4, and I guess we should
try not to crash if vo_opengl_old runs on a system with GL 1.1 drivers
only.
This commit is contained in:
wm4 2013-11-10 03:14:13 +01:00
parent 9e40d7155c
commit 775e08ba65
3 changed files with 16 additions and 5 deletions

View File

@ -263,6 +263,8 @@ struct gl_functions gl_functions[] = {
DEF_FN(UniformMatrix2fv), DEF_FN(UniformMatrix2fv),
DEF_FN(UniformMatrix3fv), DEF_FN(UniformMatrix3fv),
DEF_FN(TexImage3D), DEF_FN(TexImage3D),
// Added in OpenGL 1.4, but vo_opengl_old doesn't need it
DEF_FN(BlendFuncSeparate),
{0}, {0},
}, },
}, },

View File

@ -249,6 +249,7 @@ struct GL {
void (GLAPIENTRY *DrawBuffer)(GLenum); void (GLAPIENTRY *DrawBuffer)(GLenum);
void (GLAPIENTRY *DepthMask)(GLboolean); void (GLAPIENTRY *DepthMask)(GLboolean);
void (GLAPIENTRY *BlendFunc)(GLenum, GLenum); void (GLAPIENTRY *BlendFunc)(GLenum, GLenum);
void (GLAPIENTRY *BlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum);
void (GLAPIENTRY *Flush)(void); void (GLAPIENTRY *Flush)(void);
void (GLAPIENTRY *Finish)(void); void (GLAPIENTRY *Finish)(void);
void (GLAPIENTRY *PixelStorei)(GLenum, GLint); void (GLAPIENTRY *PixelStorei)(GLenum, GLint);

View File

@ -29,10 +29,12 @@ struct osd_fmt_entry {
GLenum type; GLenum type;
}; };
// glBlendFunc() arguments // glBlendFuncSeparate() arguments
static const int blend_factors[SUBBITMAP_COUNT][2] = { static const int blend_factors[SUBBITMAP_COUNT][4] = {
[SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
[SUBBITMAP_RGBA] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
[SUBBITMAP_RGBA] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
}; };
static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = {
@ -230,7 +232,13 @@ void mpgl_osd_set_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p)
gl->BindTexture(GL_TEXTURE_2D, p->texture); gl->BindTexture(GL_TEXTURE_2D, p->texture);
gl->Enable(GL_BLEND); gl->Enable(GL_BLEND);
gl->BlendFunc(blend_factors[p->format][0], blend_factors[p->format][1]);
const int *factors = &blend_factors[p->format][0];
if (gl->BlendFuncSeparate) {
gl->BlendFuncSeparate(factors[0], factors[1], factors[2], factors[3]);
} else {
gl->BlendFunc(factors[0], factors[1]);
}
} }
void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p)