]> git.sesse.net Git - vlc/blob - modules/video_output/glx.c
flac: don't overwrite bitspersample
[vlc] / modules / video_output / glx.c
1 /**
2  * @file glx.c
3  * @brief GLX OpenGL extension module
4  */
5 /*****************************************************************************
6  * Copyright © 2010-2012 Rémi Denis-Courmont
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <GL/glx.h>
30 #include <GL/glxext.h>
31
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>
37
38 static int Open (vlc_object_t *);
39 static void Close (vlc_object_t *);
40
41 vlc_module_begin ()
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)
48 vlc_module_end ()
49
50 typedef struct vlc_gl_sys_t
51 {
52     Display *display;
53     GLXWindow win;
54     GLXContext ctx;
55 } vlc_gl_sys_t;
56
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 *);
61
62 static bool CheckGLX (vlc_object_t *vd, Display *dpy)
63 {
64     int major, minor;
65     bool ok = false;
66
67     if (!glXQueryVersion (dpy, &major, &minor))
68         msg_Dbg (vd, "GLX extension not available");
69     else
70     if (major != 1)
71         msg_Dbg (vd, "GLX extension version %d.%d unknown", major, minor);
72     else
73     if (minor < 3)
74         msg_Dbg (vd, "GLX extension version %d.%d too old", major, minor);
75     else
76     {
77         msg_Dbg (vd, "using GLX extension version %d.%d", major, minor);
78         ok = true;
79     }
80     return ok;
81 }
82
83 static bool CheckGLXext (Display *dpy, unsigned snum, const char *ext)
84 {
85     const char *exts = glXQueryExtensionsString (dpy, snum);
86     const size_t extlen = strlen (ext);
87
88     while (*exts)
89     {
90         exts += strspn (exts, " ");
91
92         size_t len = strcspn (exts, " ");
93         if (len == extlen && !memcmp (exts, ext, extlen))
94             return true;
95         exts += len;
96     }
97     return false;
98 }
99
100 static int Open (vlc_object_t *obj)
101 {
102     vlc_gl_t *gl = (vlc_gl_t *)obj;
103
104     if (!vlc_xlib_init (obj))
105         return VLC_EGENERIC;
106
107     /* Initialize GLX display */
108     Display *dpy = XOpenDisplay (gl->surface->display.x11);
109     if (dpy == NULL)
110         return VLC_EGENERIC;
111
112     vlc_gl_sys_t *sys = malloc (sizeof (*sys));
113     if (unlikely(sys == NULL))
114     {
115         XCloseDisplay (dpy);
116         return VLC_ENOMEM;
117     }
118     gl->sys = sys;
119     sys->display = dpy;
120
121     if (!CheckGLX (obj, dpy))
122         goto error;
123
124     /* Determine our pixel format */
125     XWindowAttributes wa;
126     if (!XGetWindowAttributes (dpy, gl->surface->handle.xid, &wa))
127         goto error;
128
129     const int snum = XScreenNumberOfScreen (wa.screen);
130     const VisualID visual = XVisualIDFromVisual (wa.visual);
131     static const int attr[] = {
132         GLX_RED_SIZE, 5,
133         GLX_GREEN_SIZE, 5,
134         GLX_BLUE_SIZE, 5,
135         GLX_DOUBLEBUFFER, True,
136         GLX_X_RENDERABLE, True,
137         GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
138         None
139     };
140
141     int nelem;
142     GLXFBConfig *confs = glXChooseFBConfig (dpy, snum, attr, &nelem);
143     if (confs == NULL)
144     {
145         msg_Err (obj, "cannot choose GLX frame buffer configurations");
146         goto error;
147     }
148
149     GLXFBConfig conf;
150     bool found = false;
151     for (int i = 0; i < nelem && !found; i++)
152     {
153         conf = confs[i];
154
155         XVisualInfo *vi = glXGetVisualFromFBConfig (dpy, conf);
156         if (vi == NULL)
157             continue;
158
159         if (vi->visualid == visual)
160             found = true;
161         XFree (vi);
162     }
163     XFree (confs);
164
165     if (!found)
166     {
167         msg_Err (obj, "cannot match GLX frame buffer configuration");
168         goto error;
169     }
170
171     /* Create a drawing surface */
172     sys->win = glXCreateWindow (dpy, conf, gl->surface->handle.xid, NULL);
173     if (sys->win == None)
174     {
175         msg_Err (obj, "cannot create GLX window");
176         goto error;
177     }
178
179     /* Create an OpenGL context */
180     sys->ctx = glXCreateNewContext (dpy, conf, GLX_RGBA_TYPE, NULL, True);
181     if (sys->ctx == NULL)
182     {
183         glXDestroyWindow (dpy, sys->win);
184         msg_Err (obj, "cannot create GLX context");
185         goto error;
186     }
187
188     /* Initialize OpenGL callbacks */
189     gl->sys = sys;
190     gl->makeCurrent = MakeCurrent;
191     gl->releaseCurrent = ReleaseCurrent;
192     gl->swap = SwapBuffers;
193     gl->getProcAddress = GetSymbol;
194     gl->lock = NULL;
195     gl->unlock = NULL;
196
197 #ifdef GLX_ARB_get_proc_address
198     bool is_swap_interval_set = false;
199
200     MakeCurrent (gl);
201 # ifdef GLX_SGI_swap_control
202     if (!is_swap_interval_set
203      && CheckGLXext (dpy, snum, "GLX_SGI_swap_control"))
204     {
205         PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
206             glXGetProcAddressARB ((const GLubyte *)"glXSwapIntervalSGI");
207         assert (SwapIntervalSGI != NULL);
208         is_swap_interval_set = !SwapIntervalSGI (1);
209     }
210 # endif
211 # ifdef GLX_EXT_swap_control
212     if (!is_swap_interval_set
213      && CheckGLXext (dpy, snum, "GLX_EXT_swap_control"))
214     {
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;
220     }
221 # endif
222     ReleaseCurrent (gl);
223 #endif
224
225     return VLC_SUCCESS;
226
227 error:
228     XCloseDisplay (dpy);
229     free (sys);
230     return VLC_EGENERIC;
231 }
232
233 static void Close (vlc_object_t *obj)
234 {
235     vlc_gl_t *gl = (vlc_gl_t *)obj;
236     vlc_gl_sys_t *sys = gl->sys;
237     Display *dpy = sys->display;
238
239     glXDestroyContext (dpy, sys->ctx);
240     glXDestroyWindow (dpy, sys->win);
241     XCloseDisplay (dpy);
242     free (sys);
243 }
244
245 static int MakeCurrent (vlc_gl_t *gl)
246 {
247     vlc_gl_sys_t *sys = gl->sys;
248
249     if (!glXMakeContextCurrent (sys->display, sys->win, sys->win, sys->ctx))
250         return VLC_EGENERIC;
251     return VLC_SUCCESS;
252 }
253
254 static void ReleaseCurrent (vlc_gl_t *gl)
255 {
256     vlc_gl_sys_t *sys = gl->sys;
257
258     glXMakeContextCurrent (sys->display, None, None, NULL);
259 }
260
261 static void SwapBuffers (vlc_gl_t *gl)
262 {
263     vlc_gl_sys_t *sys = gl->sys;
264
265     glXSwapBuffers (sys->display, sys->win);
266 }
267
268 static void *GetSymbol(vlc_gl_t *gl, const char *procname)
269 {
270     (void) gl;
271 #ifdef GLX_ARB_get_proc_address
272     return glXGetProcAddressARB ((const GLubyte *)procname);
273 #else
274     return NULL;
275 #endif
276 }