summaryrefslogtreecommitdiffstats
path: root/video/out/gl_x11.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-03-01 15:55:08 +0100
committerwm4 <wm4@nowhere>2013-03-28 21:46:17 +0100
commit16e951c2cdfa6710f0d5cc77b513e0f2a5f1377d (patch)
tree8c5d12be204f0f03437041b31cf7fb7272101b7f /video/out/gl_x11.c
parent3374a43998f183b585640de0a588db2431ed87ae (diff)
downloadmpv-16e951c2cdfa6710f0d5cc77b513e0f2a5f1377d.tar.bz2
mpv-16e951c2cdfa6710f0d5cc77b513e0f2a5f1377d.tar.xz
gl_common: split into platform specific files
Do this instead of stuffing all x11/cocoa/win32/wayland specific code into gl_common.c. The cocoa specific parts could probably go directly into cocoa_common.m, possibly same with wayland. Also redo how the list of backends is managed. Get rid of the GLTYPE_ constants. Instead of having a big switch() on GLTYPE_, each backend entry has a function pointer to setup the MPGLContext callback (e.g. mpgl_set_backend_x11()).
Diffstat (limited to 'video/out/gl_x11.c')
-rw-r--r--video/out/gl_x11.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/video/out/gl_x11.c b/video/out/gl_x11.c
new file mode 100644
index 0000000000..324f93499d
--- /dev/null
+++ b/video/out/gl_x11.c
@@ -0,0 +1,282 @@
+/*
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * You can alternatively redistribute this file and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ */
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#define MP_GET_GLX_WORKAROUNDS
+#include "gl_header_fixes.h"
+
+#include "x11_common.h"
+#include "gl_common.h"
+
+struct glx_context {
+ XVisualInfo *vinfo;
+ GLXContext context;
+ GLXFBConfig fbc;
+};
+
+static bool create_context_x11_old(struct MPGLContext *ctx)
+{
+ struct glx_context *glx_ctx = ctx->priv;
+ Display *display = ctx->vo->x11->display;
+ struct vo *vo = ctx->vo;
+ GL *gl = ctx->gl;
+
+ if (glx_ctx->context)
+ return true;
+
+ GLXContext new_context = glXCreateContext(display, glx_ctx->vinfo, NULL,
+ True);
+ if (!new_context) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
+ return false;
+ }
+
+ if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
+ glXDestroyContext(display, new_context);
+ return false;
+ }
+
+ void *(*getProcAddress)(const GLubyte *);
+ getProcAddress = mp_getdladdr("glXGetProcAddress");
+ if (!getProcAddress)
+ getProcAddress = mp_getdladdr("glXGetProcAddressARB");
+
+ const char *glxstr = "";
+ const char *(*glXExtStr)(Display *, int)
+ = mp_getdladdr("glXQueryExtensionsString");
+ if (glXExtStr)
+ glxstr = glXExtStr(display, ctx->vo->x11->screen);
+
+ mpgl_load_functions(gl, getProcAddress, glxstr);
+ if (!gl->GenPrograms && gl->GetString &&
+ gl->version < MPGL_VER(3, 0) &&
+ strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program"))
+ {
+ mp_msg(MSGT_VO, MSGL_WARN,
+ "Broken glXGetProcAddress detected, trying workaround\n");
+ mpgl_load_functions(gl, NULL, glxstr);
+ }
+
+ glx_ctx->context = new_context;
+
+ if (!glXIsDirect(vo->x11->display, new_context))
+ ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
+
+ return true;
+}
+
+typedef GLXContext (*glXCreateContextAttribsARBProc)
+ (Display*, GLXFBConfig, GLXContext, Bool, const int*);
+
+static bool create_context_x11_gl3(struct MPGLContext *ctx, bool debug)
+{
+ struct glx_context *glx_ctx = ctx->priv;
+ struct vo *vo = ctx->vo;
+
+ if (glx_ctx->context)
+ return true;
+
+ glXCreateContextAttribsARBProc glXCreateContextAttribsARB =
+ (glXCreateContextAttribsARBProc)
+ glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB");
+
+ const char *glxstr = "";
+ const char *(*glXExtStr)(Display *, int)
+ = mp_getdladdr("glXQueryExtensionsString");
+ if (glXExtStr)
+ glxstr = glXExtStr(vo->x11->display, vo->x11->screen);
+ bool have_ctx_ext = glxstr && !!strstr(glxstr, "GLX_ARB_create_context");
+
+ if (!(have_ctx_ext && glXCreateContextAttribsARB)) {
+ return false;
+ }
+
+ int gl_version = ctx->requested_gl_version;
+ int context_attribs[] = {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version),
+ GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version),
+ GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ GLX_CONTEXT_FLAGS_ARB, debug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
+ None
+ };
+ GLXContext context = glXCreateContextAttribsARB(vo->x11->display,
+ glx_ctx->fbc, 0, True,
+ context_attribs);
+ if (!context) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n");
+ return false;
+ }
+
+ // set context
+ if (!glXMakeCurrent(vo->x11->display, vo->x11->window, context)) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n");
+ glXDestroyContext(vo->x11->display, context);
+ return false;
+ }
+
+ glx_ctx->context = context;
+
+ mpgl_load_functions(ctx->gl, (void *)glXGetProcAddress, glxstr);
+
+ if (!glXIsDirect(vo->x11->display, context))
+ ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW;
+
+ return true;
+}
+
+// The GL3/FBC initialization code roughly follows/copies from:
+// http://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX)
+// but also uses some of the old code.
+
+static GLXFBConfig select_fb_config(struct vo *vo, const int *attribs)
+{
+ int fbcount;
+ GLXFBConfig *fbc = glXChooseFBConfig(vo->x11->display, vo->x11->screen,
+ attribs, &fbcount);
+ if (!fbc)
+ return NULL;
+
+ // The list in fbc is sorted (so that the first element is the best).
+ GLXFBConfig fbconfig = fbc[0];
+
+ XFree(fbc);
+
+ return fbconfig;
+}
+
+static bool config_window_x11(struct MPGLContext *ctx, uint32_t d_width,
+ uint32_t d_height, uint32_t flags)
+{
+ struct vo *vo = ctx->vo;
+ struct glx_context *glx_ctx = ctx->priv;
+
+ if (glx_ctx->context) {
+ // GL context and window already exist.
+ // Only update window geometry etc.
+ vo_x11_config_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width,
+ d_height, flags, "gl");
+ return true;
+ }
+
+ int glx_major, glx_minor;
+
+ // FBConfigs were added in GLX version 1.3.
+ if (!glXQueryVersion(vo->x11->display, &glx_major, &glx_minor) ||
+ (MPGL_VER(glx_major, glx_minor) < MPGL_VER(1, 3)))
+ {
+ mp_msg(MSGT_VO, MSGL_ERR, "[gl] GLX version older than 1.3.\n");
+ return false;
+ }
+
+ const int glx_attribs_stereo_value_idx = 1; // index of GLX_STEREO + 1
+ int glx_attribs[] = {
+ GLX_STEREO, False,
+ GLX_X_RENDERABLE, True,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER, True,
+ None
+ };
+ GLXFBConfig fbc = NULL;
+ if (flags & VOFLAG_STEREO) {
+ glx_attribs[glx_attribs_stereo_value_idx] = True;
+ fbc = select_fb_config(vo, glx_attribs);
+ if (!fbc) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual,"
+ " 3D will probably not work!\n");
+ glx_attribs[glx_attribs_stereo_value_idx] = False;
+ }
+ }
+ if (!fbc)
+ fbc = select_fb_config(vo, glx_attribs);
+ if (!fbc) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n");
+ return false;
+ }
+
+ glx_ctx->fbc = fbc;
+ glx_ctx->vinfo = glXGetVisualFromFBConfig(vo->x11->display, fbc);
+
+ mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n",
+ (int)glx_ctx->vinfo->visualid);
+
+ glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_RED_SIZE, &ctx->depth_r);
+ glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_GREEN_SIZE, &ctx->depth_g);
+ glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_BLUE_SIZE, &ctx->depth_b);
+
+ vo_x11_config_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width,
+ d_height, flags, "gl");
+
+ bool success = false;
+ if (ctx->requested_gl_version >= MPGL_VER(3, 0))
+ success = create_context_x11_gl3(ctx, flags & VOFLAG_GL_DEBUG);
+ if (!success)
+ success = create_context_x11_old(ctx);
+ return success;
+}
+
+
+/**
+ * \brief free the VisualInfo and GLXContext of an OpenGL context.
+ * \ingroup glcontext
+ */
+static void releaseGlContext_x11(MPGLContext *ctx)
+{
+ struct glx_context *glx_ctx = ctx->priv;
+ XVisualInfo **vinfo = &glx_ctx->vinfo;
+ GLXContext *context = &glx_ctx->context;
+ Display *display = ctx->vo->x11->display;
+ GL *gl = ctx->gl;
+ if (*vinfo)
+ XFree(*vinfo);
+ *vinfo = NULL;
+ if (*context) {
+ if (gl->Finish)
+ gl->Finish();
+ glXMakeCurrent(display, None, NULL);
+ glXDestroyContext(display, *context);
+ }
+ *context = 0;
+}
+
+static void swapGlBuffers_x11(MPGLContext *ctx)
+{
+ glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window);
+}
+
+void mpgl_set_backend_x11(MPGLContext *ctx)
+{
+ ctx->priv = talloc_zero(ctx, struct glx_context);
+ ctx->config_window = config_window_x11;
+ ctx->releaseGlContext = releaseGlContext_x11;
+ ctx->swapGlBuffers = swapGlBuffers_x11;
+ ctx->update_xinerama_info = vo_x11_update_screeninfo;
+ ctx->border = vo_x11_border;
+ ctx->check_events = vo_x11_check_events;
+ ctx->fullscreen = vo_x11_fullscreen;
+ ctx->ontop = vo_x11_ontop;
+ ctx->vo_init = vo_x11_init;
+ ctx->vo_uninit = vo_x11_uninit;
+}