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 #ifndef GLX_ARB_get_proc_address
39 #error GLX_ARB_get_proc_address extension missing
42 typedef struct vlc_gl_sys_t
49 static int MakeCurrent (vlc_gl_t
*gl
)
51 vlc_gl_sys_t
*sys
= gl
->sys
;
53 if (!glXMakeContextCurrent (sys
->display
, sys
->win
, sys
->win
, sys
->ctx
))
58 static void ReleaseCurrent (vlc_gl_t
*gl
)
60 vlc_gl_sys_t
*sys
= gl
->sys
;
62 glXMakeContextCurrent (sys
->display
, None
, None
, NULL
);
65 static void SwapBuffers (vlc_gl_t
*gl
)
67 vlc_gl_sys_t
*sys
= gl
->sys
;
69 glXSwapBuffers (sys
->display
, sys
->win
);
72 static void *GetSymbol(vlc_gl_t
*gl
, const char *procname
)
75 return glXGetProcAddressARB ((const GLubyte
*)procname
);
78 static bool CheckGLX (vlc_object_t
*vd
, Display
*dpy
)
83 if (!glXQueryVersion (dpy
, &major
, &minor
))
84 msg_Dbg (vd
, "GLX extension not available");
87 msg_Dbg (vd
, "GLX extension version %d.%d unknown", major
, minor
);
90 msg_Dbg (vd
, "GLX extension version %d.%d too old", major
, minor
);
93 msg_Dbg (vd
, "using GLX extension version %d.%d", major
, minor
);
99 static bool CheckGLXext (Display
*dpy
, unsigned snum
, const char *ext
)
101 const char *exts
= glXQueryExtensionsString (dpy
, snum
);
102 const size_t extlen
= strlen (ext
);
106 exts
+= strspn (exts
, " ");
108 size_t len
= strcspn (exts
, " ");
109 if (len
== extlen
&& !memcmp (exts
, ext
, extlen
))
116 static void Close(vlc_gl_t
*gl
)
118 vlc_gl_sys_t
*sys
= gl
->sys
;
119 Display
*dpy
= sys
->display
;
121 glXDestroyContext(dpy
, sys
->ctx
);
122 glXDestroyWindow(dpy
, sys
->win
);
127 static int Open(vlc_gl_t
*gl
, unsigned width
, unsigned height
)
129 vlc_object_t
*obj
= VLC_OBJECT(gl
);
131 if (gl
->surface
->type
!= VOUT_WINDOW_TYPE_XID
|| !vlc_xlib_init (obj
))
134 /* Initialize GLX display */
135 Display
*dpy
= XOpenDisplay (gl
->surface
->display
.x11
);
139 vlc_gl_sys_t
*sys
= malloc (sizeof (*sys
));
140 if (unlikely(sys
== NULL
))
148 if (!CheckGLX (obj
, dpy
))
151 /* Determine our pixel format */
152 XWindowAttributes wa
;
153 if (!XGetWindowAttributes (dpy
, gl
->surface
->handle
.xid
, &wa
))
156 const int snum
= XScreenNumberOfScreen (wa
.screen
);
157 const VisualID visual
= XVisualIDFromVisual (wa
.visual
);
158 static const int attr
[] = {
162 GLX_DOUBLEBUFFER
, True
,
163 GLX_X_RENDERABLE
, True
,
164 GLX_DRAWABLE_TYPE
, GLX_WINDOW_BIT
,
169 GLXFBConfig
*confs
= glXChooseFBConfig (dpy
, snum
, attr
, &nelem
);
172 msg_Err (obj
, "cannot choose GLX frame buffer configurations");
178 for (int i
= 0; i
< nelem
&& !found
; i
++)
182 XVisualInfo
*vi
= glXGetVisualFromFBConfig (dpy
, conf
);
186 if (vi
->visualid
== visual
)
194 msg_Err (obj
, "cannot match GLX frame buffer configuration");
198 /* Create a drawing surface */
199 sys
->win
= glXCreateWindow (dpy
, conf
, gl
->surface
->handle
.xid
, NULL
);
200 if (sys
->win
== None
)
202 msg_Err (obj
, "cannot create GLX window");
206 /* Create an OpenGL context */
207 sys
->ctx
= glXCreateNewContext (dpy
, conf
, GLX_RGBA_TYPE
, NULL
, True
);
208 if (sys
->ctx
== NULL
)
210 glXDestroyWindow (dpy
, sys
->win
);
211 msg_Err (obj
, "cannot create GLX context");
215 /* Initialize OpenGL callbacks */
217 gl
->make_current
= MakeCurrent
;
218 gl
->release_current
= ReleaseCurrent
;
220 gl
->swap
= SwapBuffers
;
221 gl
->get_proc_address
= GetSymbol
;
224 bool is_swap_interval_set
= false;
227 # ifdef GLX_SGI_swap_control
228 if (!is_swap_interval_set
229 && CheckGLXext (dpy
, snum
, "GLX_SGI_swap_control"))
231 PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI
= (PFNGLXSWAPINTERVALSGIPROC
)
232 glXGetProcAddressARB ((const GLubyte
*)"glXSwapIntervalSGI");
233 assert (SwapIntervalSGI
!= NULL
);
234 is_swap_interval_set
= !SwapIntervalSGI (1);
237 # ifdef GLX_EXT_swap_control
238 if (!is_swap_interval_set
239 && CheckGLXext (dpy
, snum
, "GLX_EXT_swap_control"))
241 PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT
= (PFNGLXSWAPINTERVALEXTPROC
)
242 glXGetProcAddress ((const GLubyte
*)"glXSwapIntervalEXT");
243 assert (SwapIntervalEXT
!= NULL
);
244 SwapIntervalEXT (dpy
, sys
->win
, 1);
245 is_swap_interval_set
= true;
250 /* XXX: Prevent other gl backends (like EGL) to be opened within the same
251 * X11 window instance. Indeed, using EGL after GLX on the same X11 window
252 * instance leads to an SEGFAULT in the libEGL_nvidia.so library. */
253 const char *vendor
= glXGetClientString(dpy
, GLX_VENDOR
);
254 if (vendor
&& strncmp(vendor
, "NVIDIA", sizeof("NVIDIA") - 1) == 0)
256 var_Create(gl
->surface
, "gl", VLC_VAR_STRING
);
257 var_SetString(gl
->surface
, "gl", "glx");
260 (void) width
; (void) height
;
270 set_shortname (N_("GLX"))
271 set_description (N_("GLX extension for OpenGL"))
272 set_category (CAT_VIDEO
)
273 set_subcategory (SUBCAT_VIDEO_VOUT
)
274 set_capability ("opengl", 20)