qt: playlist: use item title if available
[vlc.git] / modules / video_output / glx.c
blob897660910fbd9a8ce4f94fea2875e9bdf489b70f
1 /**
2 * @file glx.c
3 * @brief GLX OpenGL extension module
4 */
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <GL/glx.h>
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>
36 #include <vlc_xlib.h>
38 #ifndef GLX_ARB_get_proc_address
39 #error GLX_ARB_get_proc_address extension missing
40 #endif
42 typedef struct vlc_gl_sys_t
44 Display *display;
45 GLXWindow win;
46 GLXContext ctx;
47 } 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))
54 return VLC_EGENERIC;
55 return VLC_SUCCESS;
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)
74 (void) gl;
75 return glXGetProcAddressARB ((const GLubyte *)procname);
78 static bool CheckGLX (vlc_object_t *vd, Display *dpy)
80 int major, minor;
81 bool ok = false;
83 if (!glXQueryVersion (dpy, &major, &minor))
84 msg_Dbg (vd, "GLX extension not available");
85 else
86 if (major != 1)
87 msg_Dbg (vd, "GLX extension version %d.%d unknown", major, minor);
88 else
89 if (minor < 3)
90 msg_Dbg (vd, "GLX extension version %d.%d too old", major, minor);
91 else
93 msg_Dbg (vd, "using GLX extension version %d.%d", major, minor);
94 ok = true;
96 return ok;
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);
104 while (*exts)
106 exts += strspn (exts, " ");
108 size_t len = strcspn (exts, " ");
109 if (len == extlen && !memcmp (exts, ext, extlen))
110 return true;
111 exts += len;
113 return false;
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);
123 XCloseDisplay(dpy);
124 free(sys);
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))
132 return VLC_EGENERIC;
134 /* Initialize GLX display */
135 Display *dpy = XOpenDisplay (gl->surface->display.x11);
136 if (dpy == NULL)
137 return VLC_EGENERIC;
139 vlc_gl_sys_t *sys = malloc (sizeof (*sys));
140 if (unlikely(sys == NULL))
142 XCloseDisplay (dpy);
143 return VLC_ENOMEM;
145 gl->sys = sys;
146 sys->display = dpy;
148 if (!CheckGLX (obj, dpy))
149 goto error;
151 /* Determine our pixel format */
152 XWindowAttributes wa;
153 if (!XGetWindowAttributes (dpy, gl->surface->handle.xid, &wa))
154 goto error;
156 const int snum = XScreenNumberOfScreen (wa.screen);
157 const VisualID visual = XVisualIDFromVisual (wa.visual);
158 static const int attr[] = {
159 GLX_RED_SIZE, 5,
160 GLX_GREEN_SIZE, 5,
161 GLX_BLUE_SIZE, 5,
162 GLX_DOUBLEBUFFER, True,
163 GLX_X_RENDERABLE, True,
164 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
165 None
168 int nelem;
169 GLXFBConfig *confs = glXChooseFBConfig (dpy, snum, attr, &nelem);
170 if (confs == NULL)
172 msg_Err (obj, "cannot choose GLX frame buffer configurations");
173 goto error;
176 GLXFBConfig conf;
177 bool found = false;
178 for (int i = 0; i < nelem && !found; i++)
180 conf = confs[i];
182 XVisualInfo *vi = glXGetVisualFromFBConfig (dpy, conf);
183 if (vi == NULL)
184 continue;
186 if (vi->visualid == visual)
187 found = true;
188 XFree (vi);
190 XFree (confs);
192 if (!found)
194 msg_Err (obj, "cannot match GLX frame buffer configuration");
195 goto error;
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");
203 goto error;
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");
212 goto error;
215 /* Initialize OpenGL callbacks */
216 gl->sys = sys;
217 gl->make_current = MakeCurrent;
218 gl->release_current = ReleaseCurrent;
219 gl->resize = NULL;
220 gl->swap = SwapBuffers;
221 gl->get_proc_address = GetSymbol;
222 gl->destroy = Close;
224 bool is_swap_interval_set = false;
226 MakeCurrent (gl);
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);
236 # endif
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;
247 # endif
248 ReleaseCurrent (gl);
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;
261 return VLC_SUCCESS;
263 error:
264 XCloseDisplay (dpy);
265 free (sys);
266 return VLC_EGENERIC;
269 vlc_module_begin ()
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)
275 set_callback(Open)
276 vlc_module_end ()