]> git.sesse.net Git - vlc/blob - modules/video_output/x11/glx.c
* initialize variables and don't use arguments that failed being created.
[vlc] / modules / video_output / x11 / glx.c
1 /*****************************************************************************
2  * glx.c: GLX OpenGL provider
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34 #include <vlc/vout.h>
35
36 #ifdef HAVE_SYS_SHM_H
37 #   include <sys/shm.h>                                /* shmget(), shmctl() */
38 #endif
39
40 #include <X11/Xlib.h>
41 #include <X11/Xmd.h>
42 #include <X11/Xutil.h>
43 #include <X11/keysym.h>
44 #ifdef HAVE_SYS_SHM_H
45 #   include <X11/extensions/XShm.h>
46 #endif
47 #ifdef DPMSINFO_IN_DPMS_H
48 #   include <X11/extensions/dpms.h>
49 #endif
50
51 #include <GL/glx.h>
52
53 #include "xcommon.h"
54
55 /* RV16 */
56 //#define VLCGL_RGB_FORMAT GL_RGB
57 //#define VLCGL_RGB_TYPE GL_UNSIGNED_SHORT_5_6_5
58
59 /* RV24 */
60 //#define VLCGL_RGB_FORMAT GL_RGB
61 //#define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
62
63 /* RV32 */
64 #define VLCGL_RGB_FORMAT GL_RGBA
65 #define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
66
67
68 /*****************************************************************************
69  * OpenGL provider interface
70  *****************************************************************************/
71 static int  CreateOpenGL ( vlc_object_t * );
72 static void DestroyOpenGL( vlc_object_t * );
73 static int  InitOpenGL   ( vout_thread_t * );
74 static void SwapBuffers  ( vout_thread_t * );
75
76 /*****************************************************************************
77  * Local prototypes
78  *****************************************************************************/
79 static int  CheckGLX     ( vlc_object_t *, vlc_bool_t * );
80 static int  InitGLX12    ( vout_thread_t * );
81 static int  InitGLX13    ( vout_thread_t * );
82 static void SwitchContext( vout_thread_t * );
83
84 /*****************************************************************************
85  * Module descriptor
86  *****************************************************************************/
87 #define ADAPTOR_TEXT N_("XVideo adaptor number")
88 #define ADAPTOR_LONGTEXT N_( \
89     "If you graphics card provides several adaptors, this option allows you " \
90     "to choose which one will be used (you shouldn't have to change this).")
91
92 #define ALT_FS_TEXT N_("Alternate fullscreen method")
93 #define ALT_FS_LONGTEXT N_( \
94     "There are two ways to make a fullscreen window, unfortunately each one " \
95     "has its drawbacks.\n" \
96     "1) Let the window manager handle your fullscreen window (default), but " \
97     "things like taskbars will likely show on top of the video.\n" \
98     "2) Completely bypass the window manager, but then nothing will be able " \
99     "to show on top of the video.")
100
101 #define DISPLAY_TEXT N_("X11 display name")
102 #define DISPLAY_LONGTEXT N_( \
103     "Specify the X11 hardware display you want to use. By default VLC will " \
104     "use the value of the DISPLAY environment variable.")
105
106 #define SCREEN_TEXT N_("Screen to be used for fullscreen mode.")
107 #define SCREEN_LONGTEXT N_( \
108     "Choose the screen you want to use in fullscreen mode. For instance " \
109     "set it to 0 for first screen, 1 for the second.")
110
111 vlc_module_begin();
112     set_description( _("X11 OpenGL provider") );
113     set_capability( "opengl provider", 50 );
114     set_callbacks( CreateOpenGL, DestroyOpenGL );
115
116     add_string( "glx-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
117     add_integer( "glx-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT, VLC_TRUE );
118     add_bool( "glx-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT, VLC_TRUE );
119 #ifdef HAVE_XINERAMA
120     add_integer ( "glx-xineramascreen", 0, NULL, SCREEN_TEXT, SCREEN_LONGTEXT, VLC_TRUE );
121 #endif
122 vlc_module_end();
123
124 /*****************************************************************************
125  * Exported prototypes
126  *****************************************************************************/
127 extern int  E_(Activate)   ( vlc_object_t * );
128 extern void E_(Deactivate) ( vlc_object_t * );
129
130 /*****************************************************************************
131  * CreateOpenGL: initialize an OpenGL provider
132  *****************************************************************************/
133 static int CreateOpenGL( vlc_object_t *p_this )
134 {
135     vout_thread_t *p_vout = (vout_thread_t *)p_this;
136     vlc_bool_t b_glx13;
137
138     if( CheckGLX( p_this, &b_glx13 ) != VLC_SUCCESS )
139     {
140         msg_Err( p_vout, "no GLX support" );
141         return VLC_EGENERIC;
142     }
143
144     if( E_(Activate)( p_this ) != VLC_SUCCESS )
145     {
146         return VLC_EGENERIC;
147     }
148
149     /* Set the function pointer */
150     p_vout->pf_init = InitOpenGL;
151     p_vout->pf_swap = SwapBuffers;
152     p_vout->p_sys->b_glx13 = b_glx13;
153
154     return VLC_SUCCESS;
155 }
156
157 /*****************************************************************************
158  * DestroyOpenGL: destroys an OpenGL provider
159  *****************************************************************************/
160 static void DestroyOpenGL( vlc_object_t *p_this )
161 {
162     vout_thread_t *p_vout = (vout_thread_t *)p_this;
163     vout_sys_t *p_sys = p_vout->p_sys;
164
165     glXDestroyContext( p_sys->p_display, p_sys->gwctx );
166     if( p_sys->b_glx13 )
167     {
168         glXDestroyWindow( p_sys->p_display, p_sys->gwnd );
169     }
170
171     E_(Deactivate)( p_this );
172 }
173
174 /*****************************************************************************
175  * OpenDisplay: open and initialize OpenGL device
176  *****************************************************************************/
177 static int CheckGLX( vlc_object_t *p_this, vlc_bool_t *b_glx13 )
178 {
179     Display *p_display = NULL;
180     int i_opcode, i_evt, i_err = 0;
181     int i_maj, i_min = 0;
182
183     /* Open the display */
184     p_display = XOpenDisplay( NULL );
185     if( p_display == NULL )
186     {
187         msg_Err( p_this, "Cannot open display" );
188         return VLC_EGENERIC;
189     }
190
191     /* Check for GLX extension */
192     if( !XQueryExtension( p_display, "GLX", &i_opcode, &i_evt, &i_err ) )
193     {
194         msg_Err( p_this, "GLX extension not supported" );
195         XCloseDisplay( p_display );
196         return VLC_EGENERIC;
197     }
198     if( !glXQueryExtension( p_display, &i_err, &i_evt ) )
199     {
200         msg_Err( p_this, "glXQueryExtension failed" );
201         XCloseDisplay( p_display );
202         return VLC_EGENERIC;
203     }
204
205     /* Check GLX version */
206     if (!glXQueryVersion( p_display, &i_maj, &i_min ) )
207     {
208         msg_Err( p_this, "glXQueryVersion failed" );
209         XCloseDisplay( p_display );
210         return VLC_EGENERIC;
211     }
212     if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
213     {
214         *b_glx13 = VLC_FALSE;
215         msg_Dbg( p_this, "Using GLX 1.2 API" );
216     }
217     else
218     {
219         *b_glx13 = VLC_TRUE;
220         msg_Dbg( p_this, "Using GLX 1.3 API" );
221     }
222
223     XCloseDisplay( p_display );
224     return VLC_SUCCESS;
225 }
226
227 /*****************************************************************************
228  * InitOpenGL: initializes OpenGL provider
229  *****************************************************************************/
230 static int InitOpenGL( vout_thread_t *p_vout )
231 {
232     /* Initialize GLX */
233     if( !p_vout->p_sys->b_glx13 )
234     {
235         if( InitGLX12( p_vout ) != VLC_SUCCESS )
236         {
237             return VLC_EGENERIC;
238         }
239     }
240     else
241     {
242         if( InitGLX13( p_vout ) != VLC_SUCCESS )
243         {
244             return VLC_EGENERIC;
245         }
246     }
247
248     /* Set the OpenGL context _for the current thread_ */
249     SwitchContext( p_vout );
250
251     return VLC_SUCCESS;
252 }
253
254 int InitGLX12( vout_thread_t *p_vout )
255 {
256     vout_sys_t *p_sys = p_vout->p_sys;
257     XVisualInfo *p_vi;
258     int p_attr[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
259                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, 0 };
260
261     p_vi = glXChooseVisual( p_sys->p_display,
262                             DefaultScreen( p_sys->p_display), p_attr );
263     if(! p_vi )
264     {
265         msg_Err( p_vout, "Cannot get GLX 1.2 visual" );
266         return VLC_EGENERIC;
267     }
268
269     /* Create an OpenGL context */
270     p_sys->gwctx = glXCreateContext( p_sys->p_display, p_vi, 0, True );
271     XFree( p_vi );
272     if( !p_sys->gwctx )
273     {
274         msg_Err( p_vout, "Cannot create OpenGL context");
275         return VLC_EGENERIC;
276     }
277
278     return VLC_SUCCESS;
279 }
280
281 int InitGLX13( vout_thread_t *p_vout )
282 {
283     vout_sys_t *p_sys = p_vout->p_sys;
284     int i_nbelem;
285     GLXFBConfig *p_fbconfs, fbconf;
286     XVisualInfo *p_vi;
287     int p_attr[] = { GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
288                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, True,
289                      GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0 };
290
291     /* Get the FB configuration */
292     p_fbconfs = glXChooseFBConfig( p_sys->p_display, 0, p_attr, &i_nbelem );
293     if( (i_nbelem <= 0) || !p_fbconfs )
294     {
295         msg_Err( p_vout, "Cannot get FB configurations");
296         if( p_fbconfs ) XFree( p_fbconfs );
297         return VLC_EGENERIC;
298     }
299     fbconf = p_fbconfs[0];
300
301     /* Get the X11 visual */
302     p_vi = glXGetVisualFromFBConfig( p_sys->p_display, fbconf );
303     if( !p_vi )
304     {
305         msg_Err( p_vout, "Cannot get X11 visual" );
306         XFree( p_fbconfs );
307         return VLC_EGENERIC;
308     }
309     XFree( p_vi );
310
311     /* Create the GLX window */
312     p_sys->gwnd = glXCreateWindow( p_sys->p_display, fbconf,
313                                    p_sys->p_win->video_window, NULL );
314     if( p_sys->gwnd == None )
315     {
316         msg_Err( p_vout, "Cannot create GLX window" );
317         return VLC_EGENERIC;
318     }
319
320     /* Create an OpenGL context */
321     p_sys->gwctx = glXCreateNewContext( p_sys->p_display, fbconf,
322                                         GLX_RGBA_TYPE, NULL, True );
323     XFree( p_fbconfs );
324     if( !p_sys->gwctx )
325     {
326         msg_Err( p_vout, "Cannot create OpenGL context");
327         return VLC_EGENERIC;
328     }
329
330     return VLC_SUCCESS;
331 }
332
333 /*****************************************************************************
334  * SwapBuffers: swap front/back buffers
335  *****************************************************************************/
336 static void SwapBuffers( vout_thread_t *p_vout )
337 {
338     vout_sys_t *p_sys = p_vout->p_sys;
339     int i_width, i_height, i_x, i_y;
340
341     vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
342                        p_vout->p_sys->p_win->i_height,
343                        &i_x, &i_y, &i_width, &i_height );
344
345     glViewport( 0, 0, (GLint)i_width, (GLint)i_height );
346
347     if( p_sys->b_glx13 )
348     {
349         glXSwapBuffers( p_sys->p_display, p_sys->gwnd );
350     }
351     else
352     {
353         glXSwapBuffers( p_sys->p_display, p_sys->p_win->video_window );
354     }
355 }
356
357 void SwitchContext( vout_thread_t *p_vout )
358 {
359     vout_sys_t *p_sys = p_vout->p_sys;
360
361     /* Change the current OpenGL context */
362     if( p_sys->b_glx13 )
363     {
364         glXMakeContextCurrent( p_sys->p_display, p_sys->gwnd,
365                                p_sys->gwnd, p_sys->gwctx );
366     }
367     else
368     {
369         glXMakeCurrent( p_sys->p_display, p_sys->p_win->video_window,
370                         p_sys->gwctx );
371     }
372 }