1
0
mirror of https://github.com/mpv-player/mpv synced 2025-02-03 21:52:12 +00:00
mpv/video/out/opengl/hwdec_vaglx.c
wm4 ae4c0134ed vo_opengl: do not use vaapi-over-GLX
This backend is selected if vaapi is available, but vaapi-over-EGL is
not. This causes various issues around the forced RGB conversion, which
is done with fixed, usually incorrect parameters.

It seems the existing auto probing check is too weak, and doesn't really
prevent it from getting loaded. Fix this by adding a flag to not ever
load this during auto probing.

I'm still not deleting it, because it's useful for testing on nvidia
machines.

See #4555.
2017-07-07 12:29:29 +02:00

210 lines
5.9 KiB
C

/*
* This file is part of mpv.
*
* Parts based on the MPlayer VA-API patch (see vo_vaapi.c).
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <GL/glx.h>
#include <va/va_x11.h>
#include "video/out/x11_common.h"
#include "hwdec.h"
#include "video/vaapi.h"
struct priv {
struct mp_log *log;
struct mp_vaapi_ctx *ctx;
VADisplay *display;
Display *xdisplay;
GLuint gl_texture;
GLXFBConfig fbc;
Pixmap pixmap;
GLXPixmap glxpixmap;
void (*glXBindTexImage)(Display *dpy, GLXDrawable draw, int buffer, int *a);
void (*glXReleaseTexImage)(Display *dpy, GLXDrawable draw, int buffer);
};
static void destroy_texture(struct gl_hwdec *hw)
{
struct priv *p = hw->priv;
GL *gl = hw->gl;
if (p->glxpixmap) {
p->glXReleaseTexImage(p->xdisplay, p->glxpixmap, GLX_FRONT_EXT);
glXDestroyPixmap(p->xdisplay, p->glxpixmap);
}
p->glxpixmap = 0;
if (p->pixmap)
XFreePixmap(p->xdisplay, p->pixmap);
p->pixmap = 0;
gl->DeleteTextures(1, &p->gl_texture);
p->gl_texture = 0;
}
static void destroy(struct gl_hwdec *hw)
{
struct priv *p = hw->priv;
destroy_texture(hw);
if (p->ctx)
hwdec_devices_remove(hw->devs, &p->ctx->hwctx);
va_destroy(p->ctx);
}
static int create(struct gl_hwdec *hw)
{
Display *x11disp = glXGetCurrentDisplay();
if (!x11disp)
return -1;
int x11scr = DefaultScreen(x11disp);
struct priv *p = talloc_zero(hw, struct priv);
hw->priv = p;
p->log = hw->log;
p->xdisplay = x11disp;
const char *glxext = glXQueryExtensionsString(x11disp, x11scr);
if (!glxext || !strstr(glxext, "GLX_EXT_texture_from_pixmap"))
return -1;
p->glXBindTexImage =
(void*)glXGetProcAddressARB((void*)"glXBindTexImageEXT");
p->glXReleaseTexImage =
(void*)glXGetProcAddressARB((void*)"glXReleaseTexImageEXT");
if (!p->glXBindTexImage || !p->glXReleaseTexImage)
return -1;
p->display = vaGetDisplay(x11disp);
if (!p->display)
return -1;
p->ctx = va_initialize(p->display, p->log, true);
if (!p->ctx) {
vaTerminate(p->display);
return -1;
}
int attribs[] = {
GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
GLX_Y_INVERTED_EXT, True,
GLX_DOUBLEBUFFER, False,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 0,
None
};
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig(x11disp, x11scr, attribs, &fbcount);
if (fbcount)
p->fbc = fbc[0];
if (fbc)
XFree(fbc);
if (!fbcount) {
MP_VERBOSE(p, "No texture-from-pixmap support.\n");
destroy(hw);
return -1;
}
p->ctx->hwctx.driver_name = hw->driver->name;
hwdec_devices_add(hw->devs, &p->ctx->hwctx);
return 0;
}
static int reinit(struct gl_hwdec *hw, struct mp_image_params *params)
{
struct priv *p = hw->priv;
GL *gl = hw->gl;
destroy_texture(hw);
gl->GenTextures(1, &p->gl_texture);
gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->BindTexture(GL_TEXTURE_2D, 0);
p->pixmap = XCreatePixmap(p->xdisplay,
RootWindow(p->xdisplay, DefaultScreen(p->xdisplay)),
params->w, params->h, 24);
if (!p->pixmap) {
MP_FATAL(hw, "could not create pixmap\n");
return -1;
}
int attribs[] = {
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
GLX_MIPMAP_TEXTURE_EXT, False,
None,
};
p->glxpixmap = glXCreatePixmap(p->xdisplay, p->fbc, p->pixmap, attribs);
gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
p->glXBindTexImage(p->xdisplay, p->glxpixmap, GLX_FRONT_EXT, NULL);
gl->BindTexture(GL_TEXTURE_2D, 0);
params->imgfmt = IMGFMT_RGB0;
params->hw_subfmt = 0;
return 0;
}
static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image,
struct gl_hwdec_frame *out_frame)
{
struct priv *p = hw->priv;
VAStatus status;
if (!p->pixmap)
return -1;
status = vaPutSurface(p->display, va_surface_id(hw_image), p->pixmap,
0, 0, hw_image->w, hw_image->h,
0, 0, hw_image->w, hw_image->h,
NULL, 0,
va_get_colorspace_flag(hw_image->params.color.space));
CHECK_VA_STATUS(p, "vaPutSurface()");
*out_frame = (struct gl_hwdec_frame){
.planes = {
{
.gl_texture = p->gl_texture,
.gl_target = GL_TEXTURE_2D,
.tex_w = hw_image->w,
.tex_h = hw_image->h,
},
},
};
return 0;
}
const struct gl_hwdec_driver gl_hwdec_vaglx = {
.name = "vaapi-glx",
.api = HWDEC_VAAPI,
.imgfmt = IMGFMT_VAAPI,
.testing_only = true,
.create = create,
.reinit = reinit,
.map_frame = map_frame,
.destroy = destroy,
};