3 * @brief GLX OpenGL extension module
5 /*****************************************************************************
6 * Copyright © 2010-2012 Rémi Denis-Courmont
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
30 #include <GL/glxext.h>
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_opengl.h>
35 #include <vlc_vout_window.h>
38 static int Open (vlc_object_t *);
39 static void Close (vlc_object_t *);
42 set_shortname (N_("GLX"))
43 set_description (N_("GLX extension for OpenGL"))
44 set_category (CAT_VIDEO)
45 set_subcategory (SUBCAT_VIDEO_VOUT)
46 set_capability ("opengl", 20)
47 set_callbacks (Open, Close)
50 typedef struct vlc_gl_sys_t
57 static int MakeCurrent (vlc_gl_t *);
58 static void ReleaseCurrent (vlc_gl_t *);
59 static void SwapBuffers (vlc_gl_t *);
60 static void *GetSymbol(vlc_gl_t *, const char *);
62 static bool CheckGLX (vlc_object_t *vd, Display *dpy)
67 if (!glXQueryVersion (dpy, &major, &minor))
68 msg_Dbg (vd, "GLX extension not available");
71 msg_Dbg (vd, "GLX extension version %d.%d unknown", major, minor);
74 msg_Dbg (vd, "GLX extension version %d.%d too old", major, minor);
77 msg_Dbg (vd, "using GLX extension version %d.%d", major, minor);
83 static bool CheckGLXext (Display *dpy, unsigned snum, const char *ext)
85 const char *exts = glXQueryExtensionsString (dpy, snum);
86 const size_t extlen = strlen (ext);
90 exts += strspn (exts, " ");
92 size_t len = strcspn (exts, " ");
93 if (len == extlen && !memcmp (exts, ext, extlen))
100 static int Open (vlc_object_t *obj)
102 vlc_gl_t *gl = (vlc_gl_t *)obj;
104 if (!vlc_xlib_init (obj))
107 /* Initialize GLX display */
108 Display *dpy = XOpenDisplay (gl->surface->display.x11);
112 vlc_gl_sys_t *sys = malloc (sizeof (*sys));
113 if (unlikely(sys == NULL))
121 if (!CheckGLX (obj, dpy))
124 /* Determine our pixel format */
125 XWindowAttributes wa;
126 if (!XGetWindowAttributes (dpy, gl->surface->handle.xid, &wa))
129 const int snum = XScreenNumberOfScreen (wa.screen);
130 const VisualID visual = XVisualIDFromVisual (wa.visual);
131 static const int attr[] = {
135 GLX_DOUBLEBUFFER, True,
136 GLX_X_RENDERABLE, True,
137 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
142 GLXFBConfig *confs = glXChooseFBConfig (dpy, snum, attr, &nelem);
145 msg_Err (obj, "cannot choose GLX frame buffer configurations");
151 for (int i = 0; i < nelem && !found; i++)
155 XVisualInfo *vi = glXGetVisualFromFBConfig (dpy, conf);
159 if (vi->visualid == visual)
167 msg_Err (obj, "cannot match GLX frame buffer configuration");
171 /* Create a drawing surface */
172 sys->win = glXCreateWindow (dpy, conf, gl->surface->handle.xid, NULL);
173 if (sys->win == None)
175 msg_Err (obj, "cannot create GLX window");
179 /* Create an OpenGL context */
180 sys->ctx = glXCreateNewContext (dpy, conf, GLX_RGBA_TYPE, NULL, True);
181 if (sys->ctx == NULL)
183 glXDestroyWindow (dpy, sys->win);
184 msg_Err (obj, "cannot create GLX context");
188 /* Initialize OpenGL callbacks */
190 gl->makeCurrent = MakeCurrent;
191 gl->releaseCurrent = ReleaseCurrent;
192 gl->swap = SwapBuffers;
193 gl->getProcAddress = GetSymbol;
197 #ifdef GLX_ARB_get_proc_address
198 bool is_swap_interval_set = false;
201 # ifdef GLX_SGI_swap_control
202 if (!is_swap_interval_set
203 && CheckGLXext (dpy, snum, "GLX_SGI_swap_control"))
205 PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
206 glXGetProcAddressARB ((const GLubyte *)"glXSwapIntervalSGI");
207 assert (SwapIntervalSGI != NULL);
208 is_swap_interval_set = !SwapIntervalSGI (1);
211 # ifdef GLX_EXT_swap_control
212 if (!is_swap_interval_set
213 && CheckGLXext (dpy, snum, "GLX_EXT_swap_control"))
215 PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
216 glXGetProcAddress ((const GLubyte *)"glXSwapIntervalEXT");
217 assert (SwapIntervalEXT != NULL);
218 SwapIntervalEXT (dpy, sys->win, 1);
219 is_swap_interval_set = true;
233 static void Close (vlc_object_t *obj)
235 vlc_gl_t *gl = (vlc_gl_t *)obj;
236 vlc_gl_sys_t *sys = gl->sys;
237 Display *dpy = sys->display;
239 glXDestroyContext (dpy, sys->ctx);
240 glXDestroyWindow (dpy, sys->win);
245 static int MakeCurrent (vlc_gl_t *gl)
247 vlc_gl_sys_t *sys = gl->sys;
249 if (!glXMakeContextCurrent (sys->display, sys->win, sys->win, sys->ctx))
254 static void ReleaseCurrent (vlc_gl_t *gl)
256 vlc_gl_sys_t *sys = gl->sys;
258 glXMakeContextCurrent (sys->display, None, None, NULL);
261 static void SwapBuffers (vlc_gl_t *gl)
263 vlc_gl_sys_t *sys = gl->sys;
265 glXSwapBuffers (sys->display, sys->win);
268 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
271 #ifdef GLX_ARB_get_proc_address
272 return glXGetProcAddressARB ((const GLubyte *)procname);