[vlc-commits] GLX: add OpenGL provider plugin
Rémi Denis-Courmont
git at videolan.org
Thu Oct 25 21:12:54 CEST 2012
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Thu Oct 25 21:43:35 2012 +0300| [32f2856076f8a9aeca646eeae3a2a290191f7593] | committer: Rémi Denis-Courmont
GLX: add OpenGL provider plugin
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=32f2856076f8a9aeca646eeae3a2a290191f7593
---
configure.ac | 2 +
modules/video_output/Modules.am | 7 ++
modules/video_output/glx.c | 263 +++++++++++++++++++++++++++++++++++++++
3 files changed, 272 insertions(+)
diff --git a/configure.ac b/configure.ac
index 1324da5..5ca69b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2959,6 +2959,8 @@ AS_IF([test "${enable_xcb}" != "no"], [
AC_MSG_ERROR([${GL_PKG_ERRORS}. Pass --disable-glx if you do not need OpenGL X11 support.])
])
VLC_ADD_PLUGIN([xcb_glx])
+ VLC_ADD_PLUGIN([glx])
+ VLC_ADD_PLUGIN([gl])
])
])
AM_CONDITIONAL([HAVE_XCB], [test "${have_xcb}" = "yes"])
diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am
index d8a631c..244c594 100644
--- a/modules/video_output/Modules.am
+++ b/modules/video_output/Modules.am
@@ -158,6 +158,13 @@ endif
EXTRA_LTLIBRARIES += libegl_plugin.la
libvlc_LTLIBRARIES += $(LTLIBegl)
+### GLX ###
+libglx_plugin_la_SOURCES = glx.c
+libglx_plugin_la_CFLAGS = $(AM_CFLAGS) $(GL_CFLAGS)
+libglx_plugin_la_LIBADD = $(AM_LIBADD) $(GL_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11
+EXTRA_LTLIBRARIES += libglx_plugin.la
+libvlc_LTLIBRARIES += $(LTLIBglx)
+
### Coloured ASCII art ###
libcaca_plugin_la_SOURCES = caca.c
libcaca_plugin_la_CFLAGS = $(AM_CFLAGS) $(CACA_CFLAGS)
diff --git a/modules/video_output/glx.c b/modules/video_output/glx.c
new file mode 100644
index 0000000..8aa1e08
--- /dev/null
+++ b/modules/video_output/glx.c
@@ -0,0 +1,263 @@
+/**
+ * @file glx.c
+ * @brief GLX OpenGL extension module
+ */
+/*****************************************************************************
+ * Copyright © 2010-2012 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it 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.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <GL/glx.h>
+#include <GL/glxext.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_opengl.h>
+#include <vlc_vout_window.h>
+#include <vlc_xlib.h>
+
+static int Open (vlc_object_t *);
+static void Close (vlc_object_t *);
+
+vlc_module_begin ()
+ set_shortname (N_("GLX"))
+ set_description (N_("GLX extension for OpenGL"))
+ set_category (CAT_VIDEO)
+ set_subcategory (SUBCAT_VIDEO_VOUT)
+ set_capability ("opengl", 20)
+ set_callbacks (Open, Close)
+vlc_module_end ()
+
+typedef struct vlc_gl_sys_t
+{
+ Display *display;
+ GLXWindow win;
+ GLXContext ctx;
+} vlc_gl_sys_t;
+
+static int MakeCurrent (vlc_gl_t *);
+static void SwapBuffers (vlc_gl_t *);
+static void *GetSymbol(vlc_gl_t *, const char *);
+
+static bool CheckGLX (vlc_object_t *vd, Display *dpy)
+{
+ int major, minor;
+ bool ok = false;
+
+ if (!glXQueryVersion (dpy, &major, &minor))
+ msg_Dbg (vd, "GLX extension not available");
+ else
+ if (major != 1)
+ msg_Dbg (vd, "GLX extension version %d.%d unknown", major, minor);
+ else
+ if (minor < 3)
+ msg_Dbg (vd, "GLX extension version %d.%d too old", major, minor);
+ else
+ {
+ msg_Dbg (vd, "using GLX extension version %d.%d", major, minor);
+ ok = true;
+ }
+ return ok;
+}
+
+static bool CheckGLXext (Display *dpy, unsigned snum, const char *ext)
+{
+ const char *exts = glXQueryExtensionsString (dpy, snum);
+ const size_t extlen = strlen (ext);
+
+ while (*exts)
+ {
+ exts += strspn (exts, " ");
+
+ size_t len = strcspn (exts, " ");
+ if (len == extlen && !memcmp (exts, ext, extlen))
+ return true;
+ exts += len;
+ }
+ return false;
+}
+
+static int Open (vlc_object_t *obj)
+{
+ vlc_gl_t *gl = (vlc_gl_t *)obj;
+
+ if (!vlc_xlib_init (obj))
+ return VLC_EGENERIC;
+
+ /* Initialize GLX display */
+ Display *dpy = XOpenDisplay (gl->surface->display.x11);
+ if (dpy == NULL)
+ return VLC_EGENERIC;
+
+ vlc_gl_sys_t *sys = malloc (sizeof (*sys));
+ if (unlikely(sys == NULL))
+ {
+ XCloseDisplay (dpy);
+ return VLC_ENOMEM;
+ }
+ gl->sys = sys;
+ sys->display = dpy;
+
+ if (!CheckGLX (obj, dpy))
+ goto error;
+
+ /* Determine our pixel format */
+ XWindowAttributes wa;
+ if (!XGetWindowAttributes (dpy, gl->surface->handle.xid, &wa))
+ goto error;
+
+ const int snum = XScreenNumberOfScreen (wa.screen);
+ const VisualID visual = XVisualIDFromVisual (wa.visual);
+ static const int attr[] = {
+ GLX_RED_SIZE, 5,
+ GLX_GREEN_SIZE, 5,
+ GLX_BLUE_SIZE, 5,
+ GLX_DOUBLEBUFFER, True,
+ GLX_X_RENDERABLE, True,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ None
+ };
+
+ int nelem;
+ GLXFBConfig *confs = glXChooseFBConfig (dpy, snum, attr, &nelem);
+ if (confs == NULL)
+ {
+ msg_Err (obj, "cannot choose GLX frame buffer configurations");
+ goto error;
+ }
+
+ GLXFBConfig conf;
+ bool found = false;
+ for (int i = 0; i < nelem && !found; i++)
+ {
+ conf = confs[i];
+
+ XVisualInfo *vi = glXGetVisualFromFBConfig (dpy, conf);
+ if (vi == NULL)
+ continue;
+
+ if (vi->visualid == visual)
+ found = true;
+ XFree (vi);
+ }
+ XFree (confs);
+
+ if (!found)
+ {
+ msg_Err (obj, "cannot match GLX frame buffer configuration");
+ goto error;
+ }
+
+ /* Create a drawing surface */
+ sys->win = glXCreateWindow (dpy, conf, gl->surface->handle.xid, NULL);
+ if (sys->win == None)
+ {
+ msg_Err (obj, "cannot create GLX window");
+ goto error;
+ }
+
+ /* Create an OpenGL context */
+ sys->ctx = glXCreateNewContext (dpy, conf, GLX_RGBA_TYPE, NULL, True);
+ if (sys->ctx == NULL)
+ {
+ glXDestroyWindow (dpy, sys->win);
+ msg_Err (obj, "cannot create GLX context");
+ goto error;
+ }
+
+#ifdef GLX_ARB_get_proc_address
+ bool is_swap_interval_set = false;
+# ifdef GLX_SGI_swap_control
+ if (!is_swap_interval_set
+ && CheckGLXext (dpy, snum, "GLX_SGI_swap_control"))
+ {
+ PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
+ glXGetProcAddressARB ((const GLubyte *)"glXSwapIntervalSGI");
+ assert (SwapIntervalSGI != NULL);
+ is_swap_interval_set = !SwapIntervalSGI (1);
+ }
+# endif
+# ifdef GLX_EXT_swap_control
+ if (!is_swap_interval_set
+ && CheckGLXext (dpy, snum, "GLX_EXT_swap_control"))
+ {
+ PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
+ glXGetProcAddress ((const GLubyte *)"glXSwapIntervalEXT");
+ assert (SwapIntervalEXT != NULL);
+ SwapIntervalEXT (dpy, sys->win, 1);
+ is_swap_interval_set = true;
+ }
+# endif
+#endif
+
+ /* Initialize OpenGL callbacks */
+ gl->sys = sys;
+ gl->makeCurrent = MakeCurrent;
+ gl->swap = SwapBuffers;
+ gl->getProcAddress = GetSymbol;
+ gl->lock = NULL;
+ gl->unlock = NULL;
+ return VLC_SUCCESS;
+
+error:
+ XCloseDisplay (dpy);
+ free (sys);
+ return VLC_EGENERIC;
+}
+
+static void Close (vlc_object_t *obj)
+{
+ vlc_gl_t *gl = (vlc_gl_t *)obj;
+ vlc_gl_sys_t *sys = gl->sys;
+ Display *dpy = sys->display;
+
+ glXDestroyContext (dpy, sys->ctx);
+ glXDestroyWindow (dpy, sys->win);
+ XCloseDisplay (dpy);
+ free (sys);
+}
+
+static int MakeCurrent (vlc_gl_t *gl)
+{
+ vlc_gl_sys_t *sys = gl->sys;
+
+ if (!glXMakeContextCurrent (sys->display, sys->win, sys->win, sys->ctx))
+ return VLC_EGENERIC;
+ return VLC_SUCCESS;
+}
+
+static void SwapBuffers (vlc_gl_t *gl)
+{
+ vlc_gl_sys_t *sys = gl->sys;
+
+ glXSwapBuffers (sys->display, sys->win);
+}
+
+static void *GetSymbol(vlc_gl_t *gl, const char *procname)
+{
+ (void) gl;
+#ifdef GLX_ARB_get_proc_address
+ return glXGetProcAddressARB ((const GLubyte *)procname);
+#else
+ return NULL;
+#endif
+}
More information about the vlc-commits
mailing list