]> git.sesse.net Git - vlc/blob - modules/video_output/x11/glx.c
A bit of headers cleanup
[vlc] / modules / video_output / x11 / glx.c
1 /*****************************************************************************
2  * glx.c: GLX OpenGL provider
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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_interface.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 your graphics card provides several adaptors, you have " \
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")
102 #define DISPLAY_LONGTEXT N_( \
103     "X11 hardware display to use. By default VLC will " \
104     "use the value of the DISPLAY environment variable.")
105
106 #define SCREEN_TEXT N_("Screen for fullscreen mode.")
107 #define SCREEN_LONGTEXT N_( \
108     "Screen 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_shortname( "OpenGL(GLX)" );
113     set_category( CAT_VIDEO );
114     set_subcategory( SUBCAT_VIDEO_VOUT );
115     set_description( _("OpenGL(GLX) provider") );
116     set_capability( "opengl provider", 50 );
117     set_callbacks( CreateOpenGL, DestroyOpenGL );
118
119     add_string( "glx-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
120     add_integer( "glx-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT, VLC_TRUE );
121     add_bool( "glx-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT, VLC_TRUE );
122 #ifdef HAVE_XINERAMA
123     add_integer ( "glx-xineramascreen", 0, NULL, SCREEN_TEXT, SCREEN_LONGTEXT, VLC_TRUE );
124 #endif
125 vlc_module_end();
126
127 /*****************************************************************************
128  * Exported prototypes
129  *****************************************************************************/
130 extern int  E_(Activate)   ( vlc_object_t * );
131 extern void E_(Deactivate) ( vlc_object_t * );
132
133 /*****************************************************************************
134  * CreateOpenGL: initialize an OpenGL provider
135  *****************************************************************************/
136 static int CreateOpenGL( vlc_object_t *p_this )
137 {
138     vout_thread_t *p_vout = (vout_thread_t *)p_this;
139     vlc_bool_t b_glx13;
140
141     if( CheckGLX( p_this, &b_glx13 ) != VLC_SUCCESS )
142     {
143         msg_Err( p_vout, "no GLX support" );
144         return VLC_EGENERIC;
145     }
146
147     if( E_(Activate)( p_this ) != VLC_SUCCESS )
148     {
149         return VLC_EGENERIC;
150     }
151
152     /* Set the function pointer */
153     p_vout->pf_init = InitOpenGL;
154     p_vout->pf_swap = SwapBuffers;
155     p_vout->p_sys->b_glx13 = b_glx13;
156
157     return VLC_SUCCESS;
158 }
159
160 /*****************************************************************************
161  * DestroyOpenGL: destroys an OpenGL provider
162  *****************************************************************************/
163 static void DestroyOpenGL( vlc_object_t *p_this )
164 {
165     vout_thread_t *p_vout = (vout_thread_t *)p_this;
166     vout_sys_t *p_sys = p_vout->p_sys;
167
168     glXDestroyContext( p_sys->p_display, p_sys->gwctx );
169     if( p_sys->b_glx13 )
170     {
171         glXDestroyWindow( p_sys->p_display, p_sys->gwnd );
172     }
173
174     E_(Deactivate)( p_this );
175 }
176
177 /*****************************************************************************
178  * OpenDisplay: open and initialize OpenGL device
179  *****************************************************************************/
180 static int CheckGLX( vlc_object_t *p_this, vlc_bool_t *b_glx13 )
181 {
182     Display *p_display = NULL;
183     int i_opcode, i_evt, i_err = 0;
184     int i_maj, i_min = 0;
185
186     /* Open the display */
187     p_display = XOpenDisplay( NULL );
188     if( p_display == NULL )
189     {
190         msg_Err( p_this, "cannot open display" );
191         return VLC_EGENERIC;
192     }
193
194     /* Check for GLX extension */
195     if( !XQueryExtension( p_display, "GLX", &i_opcode, &i_evt, &i_err ) )
196     {
197         msg_Err( p_this, "GLX extension not supported" );
198         XCloseDisplay( p_display );
199         return VLC_EGENERIC;
200     }
201     if( !glXQueryExtension( p_display, &i_err, &i_evt ) )
202     {
203         msg_Err( p_this, "glXQueryExtension failed" );
204         XCloseDisplay( p_display );
205         return VLC_EGENERIC;
206     }
207
208     /* Check GLX version */
209     if (!glXQueryVersion( p_display, &i_maj, &i_min ) )
210     {
211         msg_Err( p_this, "glXQueryVersion failed" );
212         XCloseDisplay( p_display );
213         return VLC_EGENERIC;
214     }
215     if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
216     {
217         *b_glx13 = VLC_FALSE;
218         msg_Dbg( p_this, "using GLX 1.2 API" );
219     }
220     else
221     {
222         *b_glx13 = VLC_TRUE;
223         msg_Dbg( p_this, "using GLX 1.3 API" );
224     }
225
226     XCloseDisplay( p_display );
227     return VLC_SUCCESS;
228 }
229
230 /*****************************************************************************
231  * InitOpenGL: initializes OpenGL provider
232  *****************************************************************************/
233 static int InitOpenGL( vout_thread_t *p_vout )
234 {
235     /* Initialize GLX */
236     if( !p_vout->p_sys->b_glx13 )
237     {
238         if( InitGLX12( p_vout ) != VLC_SUCCESS )
239         {
240             return VLC_EGENERIC;
241         }
242     }
243     else
244     {
245         if( InitGLX13( p_vout ) != VLC_SUCCESS )
246         {
247             return VLC_EGENERIC;
248         }
249     }
250
251     /* Set the OpenGL context _for the current thread_ */
252     SwitchContext( p_vout );
253
254     return VLC_SUCCESS;
255 }
256
257 int InitGLX12( vout_thread_t *p_vout )
258 {
259     vout_sys_t *p_sys = p_vout->p_sys;
260     XVisualInfo *p_vi;
261     int p_attr[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
262                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, 0 };
263
264     p_vi = glXChooseVisual( p_sys->p_display,
265                             DefaultScreen( p_sys->p_display), p_attr );
266     if(! p_vi )
267     {
268         msg_Err( p_vout, "Cannot get GLX 1.2 visual" );
269         return VLC_EGENERIC;
270     }
271
272     /* Create an OpenGL context */
273     p_sys->gwctx = glXCreateContext( p_sys->p_display, p_vi, 0, True );
274     XFree( p_vi );
275     if( !p_sys->gwctx )
276     {
277         msg_Err( p_vout, "Cannot create OpenGL context");
278         return VLC_EGENERIC;
279     }
280
281     return VLC_SUCCESS;
282 }
283
284 int InitGLX13( vout_thread_t *p_vout )
285 {
286     vout_sys_t *p_sys = p_vout->p_sys;
287     int i_nbelem;
288     GLXFBConfig *p_fbconfs, fbconf;
289     XVisualInfo *p_vi;
290     int p_attr[] = { GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
291                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, True,
292                      GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0 };
293
294     /* Get the FB configuration */
295     p_fbconfs = glXChooseFBConfig( p_sys->p_display, 0, p_attr, &i_nbelem );
296     if( (i_nbelem <= 0) || !p_fbconfs )
297     {
298         msg_Err( p_vout, "Cannot get FB configurations");
299         if( p_fbconfs ) XFree( p_fbconfs );
300         return VLC_EGENERIC;
301     }
302     fbconf = p_fbconfs[0];
303
304     /* Get the X11 visual */
305     p_vi = glXGetVisualFromFBConfig( p_sys->p_display, fbconf );
306     if( !p_vi )
307     {
308         msg_Err( p_vout, "Cannot get X11 visual" );
309         XFree( p_fbconfs );
310         return VLC_EGENERIC;
311     }
312     XFree( p_vi );
313
314     /* Create the GLX window */
315     p_sys->gwnd = glXCreateWindow( p_sys->p_display, fbconf,
316                                    p_sys->p_win->video_window, NULL );
317     if( p_sys->gwnd == None )
318     {
319         msg_Err( p_vout, "Cannot create GLX window" );
320         return VLC_EGENERIC;
321     }
322
323     /* Create an OpenGL context */
324     p_sys->gwctx = glXCreateNewContext( p_sys->p_display, fbconf,
325                                         GLX_RGBA_TYPE, NULL, True );
326     XFree( p_fbconfs );
327     if( !p_sys->gwctx )
328     {
329         msg_Err( p_vout, "Cannot create OpenGL context");
330         return VLC_EGENERIC;
331     }
332
333     return VLC_SUCCESS;
334 }
335
336 /*****************************************************************************
337  * SwapBuffers: swap front/back buffers
338  *****************************************************************************/
339 static void SwapBuffers( vout_thread_t *p_vout )
340 {
341     vout_sys_t *p_sys = p_vout->p_sys;
342     unsigned int i_width, i_height, i_x, i_y;
343
344     vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
345                        p_vout->p_sys->p_win->i_height,
346                        &i_x, &i_y, &i_width, &i_height );
347
348     glViewport( 0, 0, (GLint)i_width, (GLint)i_height );
349
350     if( p_sys->b_glx13 )
351     {
352         glXSwapBuffers( p_sys->p_display, p_sys->gwnd );
353     }
354     else
355     {
356         glXSwapBuffers( p_sys->p_display, p_sys->p_win->video_window );
357     }
358 }
359
360 void SwitchContext( vout_thread_t *p_vout )
361 {
362     vout_sys_t *p_sys = p_vout->p_sys;
363
364     /* Change the current OpenGL context */
365     if( p_sys->b_glx13 )
366     {
367         glXMakeContextCurrent( p_sys->p_display, p_sys->gwnd,
368                                p_sys->gwnd, p_sys->gwctx );
369     }
370     else
371     {
372         glXMakeCurrent( p_sys->p_display, p_sys->p_win->video_window,
373                         p_sys->gwctx );
374     }
375 }