* all: created a new module type "opengl provider", which provides a
[vlc.git] / modules / video_output / x11 / glx.c
1 /*****************************************************************************
2  * glx.c: GLX video output
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/intf.h>
33 #include <vlc/vout.h>
34
35 /* For the opengl provider interface */
36 #include "vlc_opengl.h"
37
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <GL/glx.h>
41
42
43 /* Data common to vout and opengl provider structures */
44 typedef struct glx_t
45 {
46     Display     *p_display;
47     int         b_glx13;
48     int         i_width;
49     int         i_height;
50     int         b_fullscreen;
51     GLXContext  gwctx;
52     Window      wnd;
53     GLXWindow   gwnd;
54     Atom        wm_delete;
55 } glx_t;
56
57
58 /*****************************************************************************
59  * Vout interface
60  *****************************************************************************/
61 static int  CreateVout   ( vlc_object_t * );
62 static void DestroyVout  ( vlc_object_t * );
63 static int  Init         ( vout_thread_t * );
64 static void End          ( vout_thread_t * );
65 static int  Manage       ( vout_thread_t * );
66 static void Render       ( vout_thread_t *p_vout, picture_t *p_pic );
67 static void DisplayVideo ( vout_thread_t *, picture_t * );
68
69 /*****************************************************************************
70  * OpenGL providerinterface
71  *****************************************************************************/
72 static int  CreateOpenGL ( vlc_object_t * );
73 static void DestroyOpenGL( vlc_object_t * );
74 static int  InitOpenGL   ( opengl_t *, int, int );
75 static void SwapBuffers  ( opengl_t * );
76 static int  HandleEvents ( opengl_t * );
77
78 /*****************************************************************************
79  * Local prototypes
80  *****************************************************************************/
81 static int  OpenDisplay ( vlc_object_t *, glx_t * );
82 static void CloseDisplay( glx_t * );
83 static int  InitGLX12   ( vlc_object_t *, glx_t * );
84 static int  InitGLX13   ( vlc_object_t *, glx_t * );
85 static void CreateWindow( vlc_object_t *, glx_t *, XVisualInfo *);
86 static int  HandleX11Events( vlc_object_t *, glx_t * );
87 static void SwitchContext( glx_t * );
88
89 static inline int GetAlignedSize( int i_size );
90
91 /*****************************************************************************
92  * Module descriptor
93  *****************************************************************************/
94 vlc_module_begin();
95     set_description( _("X11 OpenGL (GLX) video output") );
96     set_capability( "video output", 20 );
97     add_shortcut( "glx" );
98     set_callbacks( CreateVout, DestroyVout );
99
100     add_submodule();
101     set_description( _("X11 OpenGL provider") );
102     set_capability( "opengl provider", 50 );
103     set_callbacks( CreateOpenGL, DestroyOpenGL );
104 vlc_module_end();
105
106
107 /*****************************************************************************
108  * vout_sys_t: GLX video output method descriptor
109  *****************************************************************************
110  * This structure is part of the video output thread descriptor.
111  * It describes the GLX specific properties of an output thread.
112  *****************************************************************************/
113 struct vout_sys_t
114 {
115     uint8_t     *p_buffer;
116     int         i_index;
117     int         i_tex_width;
118     int         i_tex_height;
119     GLuint      texture;
120     int         i_effect; //XXX
121
122     glx_t       glx;
123 };
124
125 struct opengl_sys_t
126 {
127     glx_t       glx;
128 };
129
130
131 #define MWM_HINTS_DECORATIONS   (1L << 1)
132 #define PROP_MWM_HINTS_ELEMENTS 5
133 typedef struct mwmhints_t
134 {
135     uint32_t flags;
136     uint32_t functions;
137     uint32_t decorations;
138     int32_t  input_mode;
139     uint32_t status;
140 } mwmhints_t;
141
142
143 /*****************************************************************************
144  * CreateVout: allocates GLX video thread output method
145  *****************************************************************************
146  * This function allocates and initializes a GLX vout method.
147  *****************************************************************************/
148 static int CreateVout( vlc_object_t *p_this )
149 {
150     vout_thread_t *p_vout = (vout_thread_t *)p_this;
151
152     /* Allocate structure */
153     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
154     if( p_vout->p_sys == NULL )
155     {
156         msg_Err( p_vout, "out of memory" );
157         return( 1 );
158     }
159
160     //XXX set to 0 to disable the cube effect
161     p_vout->p_sys->i_effect = 1;
162
163    /* p_vout->p_sys->glx.i_width = p_vout->i_window_width;
164     p_vout->p_sys->glx.i_height = p_vout->i_window_height; */
165     p_vout->p_sys->glx.i_width = 700;
166     p_vout->p_sys->glx.i_height = 700;
167     p_vout->p_sys->glx.b_fullscreen = 0;
168
169     /* A texture must have a size aligned on a power of 2 */
170     p_vout->p_sys->i_tex_width  = GetAlignedSize( p_vout->render.i_width );
171     p_vout->p_sys->i_tex_height = GetAlignedSize( p_vout->render.i_height );
172
173     msg_Dbg( p_vout, "Texture size: %dx%d", p_vout->p_sys->i_tex_width,
174              p_vout->p_sys->i_tex_height );
175
176     /* Open and initialize device */
177     if( OpenDisplay( p_this, &p_vout->p_sys->glx ) )
178     {
179         msg_Err( p_vout, "cannot open display" );
180         free( p_vout->p_sys );
181         return( 1 );
182     }
183
184     p_vout->pf_init = Init;
185     p_vout->pf_end = End;
186     p_vout->pf_manage = Manage;
187     p_vout->pf_render = Render;
188     p_vout->pf_display = DisplayVideo;
189
190     return( 0 );
191 }
192
193 /*****************************************************************************
194  * Init: initialize GLX video thread output method
195  *****************************************************************************/
196 static int Init( vout_thread_t *p_vout )
197 {
198     int i_index;
199     picture_t *p_pic;
200
201     /* No YUV textures :( */
202     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
203     p_vout->output.i_rmask = 0x000000ff;
204     p_vout->output.i_gmask = 0x0000ff00;
205     p_vout->output.i_bmask = 0x00ff0000;
206
207     p_vout->output.i_width  = p_vout->render.i_width;
208     p_vout->output.i_height = p_vout->render.i_height;
209     p_vout->output.i_aspect = p_vout->render.i_aspect;
210
211     I_OUTPUTPICTURES = 0;
212
213     p_pic = NULL;
214
215     /* Find an empty picture slot */
216     for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
217     {
218         if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
219         {
220             p_pic = p_vout->p_picture + i_index;
221             break;
222         }
223     }
224
225     if( p_pic == NULL )
226     {
227         return -1;
228     }
229
230    /* We know the chroma, allocate a buffer which will be used
231      * directly by the decoder */
232     p_pic->i_planes = 1;
233
234     p_vout->p_sys->p_buffer =
235         malloc( p_vout->p_sys->i_tex_width * p_vout->p_sys->i_tex_height * 4 );
236     if( !p_vout->p_sys->p_buffer )
237     {
238         msg_Err( p_vout, "Out of memory" );
239         return -1;
240     }
241
242     p_pic->p->p_pixels = p_vout->p_sys->p_buffer
243         + 2 * p_vout->p_sys->i_tex_width *
244           (p_vout->p_sys->i_tex_height - p_vout->output.i_height)
245         + 2 * (p_vout->p_sys->i_tex_width - p_vout->output.i_width);
246     p_pic->p->i_lines = p_vout->output.i_height;
247     p_pic->p->i_pitch = p_vout->p_sys->i_tex_width * 4;
248     p_pic->p->i_pixel_pitch = 4;
249     p_pic->p->i_visible_pitch = p_vout->output.i_width * 4;
250
251     p_pic->i_status = DESTROYED_PICTURE;
252     p_pic->i_type   = DIRECT_PICTURE;
253
254     PP_OUTPUTPICTURE[ 0 ] = p_pic;
255
256     I_OUTPUTPICTURES = 1;
257
258     SwitchContext( &p_vout->p_sys->glx );
259
260     /* Set the texture parameters */
261     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
262     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
263
264     if( p_vout->p_sys->i_effect )
265     {
266         glEnable( GL_CULL_FACE);
267 /*        glDisable( GL_DEPTH_TEST );
268         glEnable( GL_BLEND );
269         glBlendFunc( GL_SRC_ALPHA, GL_ONE );*/
270
271         /* Set the perpective */
272         glMatrixMode( GL_PROJECTION );
273         glLoadIdentity();
274         glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
275         glMatrixMode( GL_MODELVIEW );
276         glLoadIdentity();
277         glTranslatef( 0.0, 0.0, - 5.0 );
278     }
279
280     return 0;
281 }
282
283 /*****************************************************************************
284  * End: terminate GLX video thread output method
285  *****************************************************************************/
286 static void End( vout_thread_t *p_vout )
287 {
288     ;
289 }
290
291 /*****************************************************************************
292  * Destroy: destroy GLX video thread output method
293  *****************************************************************************
294  * Terminate an output method created by CreateVout
295  *****************************************************************************/
296 static void DestroyVout( vlc_object_t *p_this )
297 {
298     vout_thread_t *p_vout = (vout_thread_t *)p_this;
299
300     CloseDisplay( &p_vout->p_sys->glx );
301
302     /* Free the texture buffer*/
303     if( p_vout->p_sys->p_buffer )
304     {
305         free( p_vout->p_sys->p_buffer );
306     }
307
308     free( p_vout->p_sys );
309 }
310
311
312 /*****************************************************************************
313  * CreateOpenGL: initialize an OpenGL provider
314  *****************************************************************************/
315 static int CreateOpenGL( vlc_object_t *p_this )
316 {
317     opengl_t *p_opengl = (opengl_t*)p_this;
318
319     /* Allocate the structure */
320     p_opengl->p_sys = malloc(sizeof(opengl_sys_t));
321
322     /* Set the function pointers */
323     p_opengl->pf_init = InitOpenGL;
324     p_opengl->pf_swap = SwapBuffers;
325     p_opengl->pf_handle_events = HandleEvents;
326
327     p_opengl->p_sys->glx.wnd = None;
328
329     return VLC_SUCCESS;
330 }
331
332
333 /*****************************************************************************
334  * DestroyOpenGL: destroys an OpenGL provider
335  *****************************************************************************/
336 static void DestroyOpenGL( vlc_object_t *p_this )
337 {
338     opengl_t *p_opengl = (opengl_t*)p_this;
339
340     /* Free the structure */
341     free(p_opengl->p_sys);
342 }
343
344 /*****************************************************************************
345  * InitOpenGL: creates the OpenGL window
346  *****************************************************************************/
347 static int InitOpenGL( opengl_t *p_opengl, int i_width, int i_height )
348 {
349     p_opengl->p_sys->glx.i_width = i_width;
350     p_opengl->p_sys->glx.i_height = i_height;
351     p_opengl->p_sys->glx.b_fullscreen = 0;
352
353     if( OpenDisplay( (vlc_object_t*)p_opengl, &p_opengl->p_sys->glx ) )
354     {
355         msg_Err( p_opengl, "Cannot create OpenGL window" );
356         return VLC_EGENERIC;
357     }
358
359     /* Set the OpenGL context _for the current thread_ */
360     SwitchContext( &p_opengl->p_sys->glx );
361
362     return VLC_SUCCESS;
363 }
364
365
366 /*****************************************************************************
367  * SwapBuffers: swap front/back buffers
368  *****************************************************************************/
369 static void SwapBuffers( opengl_t *p_opengl )
370 {
371     if( p_opengl->p_sys->glx.b_glx13 )
372     {
373         glXSwapBuffers( p_opengl->p_sys->glx.p_display,
374                         p_opengl->p_sys->glx.gwnd );
375     }
376     else
377     {
378         glXSwapBuffers( p_opengl->p_sys->glx.p_display,
379                         p_opengl->p_sys->glx.wnd );
380     }
381 }
382
383
384 /*****************************************************************************
385  * HandleEvents: handle window events
386  *****************************************************************************/
387 static int HandleEvents( opengl_t *p_opengl )
388 {
389     int i_ret =
390         HandleX11Events( (vlc_object_t*)p_opengl, &p_opengl->p_sys->glx );
391     if( i_ret )
392     {
393         /* close the window */
394         CloseDisplay( &p_opengl->p_sys->glx );
395     }
396     return i_ret;
397 }
398
399
400 /*****************************************************************************
401  * Manage: handle X11 events
402  *****************************************************************************
403  * This function should be called regularly by video output thread. It manages
404  * console events. It returns a non null value on error.
405  *****************************************************************************/
406 static int Manage( vout_thread_t *p_vout )
407 {
408     if( HandleX11Events( (vlc_object_t*)p_vout, &p_vout->p_sys->glx ) )
409     {
410         /* the user wants to close the window */
411         playlist_t * p_playlist =
412             (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
413                                            FIND_ANYWHERE );
414         if( p_playlist != NULL )
415         {
416             playlist_Stop( p_playlist );
417             vlc_object_release( p_playlist );
418         }
419     }
420     return 0;
421 }
422
423
424 static int HandleX11Events( vlc_object_t *p_thread, glx_t *p_glx )
425 {
426     Display *p_display;
427
428     p_display = p_glx->p_display;
429
430     /* loop on X11 events */
431     while( XPending( p_display ) > 0 )
432     {
433         XEvent evt;
434         XNextEvent( p_display, &evt );
435         switch( evt.type )
436         {
437             case ClientMessage:
438             {
439                 /* Delete notification */
440                 if( (evt.xclient.format == 32) &&
441                     ((Atom)evt.xclient.data.l[0] ==
442                      p_glx->wm_delete) )
443                 {
444                     return -1;
445                 }
446                 break;
447             }
448         }
449     }
450     return 0;
451 }
452
453
454 /*****************************************************************************
455  * Render: render previously calculated output
456  *****************************************************************************/
457 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
458 {
459     glClear(GL_COLOR_BUFFER_BIT);
460     /*glTexImage2D (GL_TEXTURE_2D, 0, 3, p_vout->output.i_width,
461                   p_vout->output.i_height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
462                   p_vout->p_sys->p_buffer);*/
463     glTexImage2D (GL_TEXTURE_2D, 0, 3, p_vout->p_sys->i_tex_width,
464                   p_vout->p_sys->i_tex_height , 0, GL_RGBA, GL_UNSIGNED_BYTE,
465                   p_vout->p_sys->p_buffer);
466
467     if( !p_vout->p_sys->i_effect )
468     {
469         glEnable( GL_TEXTURE_2D);
470         glBegin( GL_POLYGON);
471         glTexCoord2f(0.0,0.0); glVertex2f(-1.0,1.0);
472         glTexCoord2f(1.0,0.0); glVertex2f(1.0,1.0);
473         glTexCoord2f(1.0,1.0); glVertex2f(1.0,-1.0);
474         glTexCoord2f(0.0,1.0); glVertex2f(-1.0,-1.0);
475         glEnd();
476     }
477     else
478     {
479         glRotatef( 1.0, 0.3, 0.5, 0.7 );
480
481         glEnable( GL_TEXTURE_2D);
482         glBegin( GL_QUADS );
483
484         float f_width = p_vout->output.i_width;
485         float f_height = p_vout->output.i_height;
486
487         /* Correct the aspect ratio */
488  /*       float f_aspect = (float)p_vout->output.i_aspect / VOUT_ASPECT_FACTOR;
489         if( f_aspect > 1.0 )
490         {
491             f_height *= f_aspect;
492         }
493         else
494         {
495             f_width *= f_aspect;
496         }*/
497
498         float f_offset_x = (1.0 - f_width / p_vout->p_sys->i_tex_width) / 2.0;
499         float f_offset_y = (1.0 - f_height / p_vout->p_sys->i_tex_height) / 2.0;
500
501         /* Front */
502         glTexCoord2f( f_offset_x, f_offset_y );
503         glVertex3f( - 1.0, 1.0, 1.0 );
504         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
505         glVertex3f( - 1.0, - 1.0, 1.0 );
506         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
507         glVertex3f( 1.0, - 1.0, 1.0 );
508         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
509         glVertex3f( 1.0, 1.0, 1.0 );
510
511         /* Left */
512         glTexCoord2f( f_offset_x, f_offset_y );
513         glVertex3f( - 1.0, 1.0, - 1.0 );
514         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
515         glVertex3f( - 1.0, - 1.0, - 1.0 );
516         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
517         glVertex3f( - 1.0, - 1.0, 1.0 );
518         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
519         glVertex3f( - 1.0, 1.0, 1.0 );
520
521         /* Back */
522         glTexCoord2f( f_offset_x, f_offset_y );
523         glVertex3f( 1.0, 1.0, - 1.0 );
524         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
525         glVertex3f( 1.0, - 1.0, - 1.0 );
526         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
527         glVertex3f( - 1.0, - 1.0, - 1.0 );
528         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
529         glVertex3f( - 1.0, 1.0, - 1.0 );
530
531         /* Right */
532         glTexCoord2f( f_offset_x, f_offset_y );
533         glVertex3f( 1.0, 1.0, 1.0 );
534         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
535         glVertex3f( 1.0, - 1.0, 1.0 );
536         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
537         glVertex3f( 1.0, - 1.0, - 1.0 );
538         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
539         glVertex3f( 1.0, 1.0, - 1.0 );
540
541         /* Top */
542         glTexCoord2f( f_offset_x, f_offset_y );
543         glVertex3f( - 1.0, 1.0, - 1.0 );
544         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
545         glVertex3f( - 1.0, 1.0, 1.0 );
546         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
547         glVertex3f( 1.0, 1.0, 1.0 );
548         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
549         glVertex3f( 1.0, 1.0, - 1.0 );
550
551         /* Bottom */
552         glTexCoord2f( f_offset_x, f_offset_y );
553         glVertex3f( - 1.0, - 1.0, 1.0 );
554         glTexCoord2f( f_offset_x, 1.0 - f_offset_y );
555         glVertex3f( - 1.0, - 1.0, - 1.0 );
556         glTexCoord2f( 1.0 - f_offset_x, 1.0 - f_offset_y );
557         glVertex3f( 1.0, - 1.0, - 1.0 );
558         glTexCoord2f( 1.0 - f_offset_x, f_offset_y );
559         glVertex3f( 1.0, - 1.0, 1.0 );
560         glEnd();
561     }
562     glDisable( GL_TEXTURE_2D);
563 }
564
565
566 /*****************************************************************************
567  * DisplayVideo: displays previously rendered output
568  *****************************************************************************/
569 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
570 {
571     if( p_vout->p_sys->glx.b_glx13 )
572     {
573         glXSwapBuffers( p_vout->p_sys->glx.p_display,
574                         p_vout->p_sys->glx.gwnd );
575     }
576     else
577     {
578         glXSwapBuffers( p_vout->p_sys->glx.p_display,
579                         p_vout->p_sys->glx.wnd );
580     }
581 }
582
583
584 /*****************************************************************************
585  * OpenDisplay: open and initialize OpenGL device
586  *****************************************************************************/
587 static int OpenDisplay( vlc_object_t *p_thread, glx_t *p_glx )
588 {
589     Display *p_display;
590     int i_opcode, i_evt, i_err;
591     int i_maj, i_min;
592
593     /* Open the display */
594     p_glx->p_display = p_display = XOpenDisplay( NULL );
595     if( !p_display )
596     {
597         msg_Err( p_thread, "Cannot open display" );
598         return -1;
599     }
600
601     /* Check for GLX extension */
602     if( !XQueryExtension( p_display, "GLX", &i_opcode, &i_evt, &i_err ) )
603     {
604         msg_Err( p_thread, "GLX extension not supported" );
605         return -1;
606     }
607     if( !glXQueryExtension( p_display, &i_err, &i_evt ) )
608     {
609         msg_Err( p_thread, "glXQueryExtension failed" );
610         return -1;
611     }
612
613     /* Check GLX version */
614     if (!glXQueryVersion( p_display, &i_maj, &i_min ) )
615     {
616         msg_Err( p_thread, "glXQueryVersion failed" );
617         return -1;
618     }
619     if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
620     {
621         p_glx->b_glx13 = 0;
622         msg_Dbg( p_thread, "Using GLX 1.2 API" );
623         if( InitGLX12( p_thread, p_glx ) == -1 )
624         {
625             return -1;
626         }
627     }
628     else
629     {
630         p_glx->b_glx13 = 1;
631         msg_Dbg( p_thread, "Using GLX 1.3 API" );
632         if( InitGLX13( p_thread, p_glx ) == -1 )
633         {
634             return -1;
635         }
636     }
637
638     XMapWindow( p_display, p_glx->wnd );
639     if( p_glx->b_fullscreen )
640     {
641         //XXX
642         XMoveWindow( p_display, p_glx->wnd, 0, 0 );
643     }
644     XFlush( p_display );
645     return 0;
646 }
647
648 /*****************************************************************************
649  * CloseDisplay: close and reset OpenGL device
650  *****************************************************************************
651  * Returns all resources allocated by OpenDisplay and restore the original
652  * state of the device.
653  *****************************************************************************/
654 static void CloseDisplay( glx_t *p_glx )
655 {
656     Display *p_display;
657
658     if (p_glx->wnd == None )
659     {
660         // Already closed or not opened...
661         return;
662     }
663
664     glFlush();
665     p_display = p_glx->p_display;
666     glXDestroyContext( p_display, p_glx->gwctx );
667     if( p_glx->b_glx13 )
668     {
669         glXDestroyWindow( p_display, p_glx->gwnd );
670     }
671     XDestroyWindow( p_display, p_glx->wnd );
672     p_glx->wnd = None;
673 }
674
675
676 int InitGLX12( vlc_object_t *p_thread, glx_t *p_glx )
677 {
678     Display *p_display;
679     XVisualInfo *p_vi;
680     GLXContext gwctx;
681     int p_attr[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
682                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER,
683                      0 };
684
685     p_display = p_glx->p_display;
686
687     p_vi = glXChooseVisual( p_display, DefaultScreen( p_display), p_attr );
688     if(! p_vi )
689     {
690         msg_Err( p_thread, "Cannot get GLX 1.2 visual" );
691         return -1;
692     }
693
694     /* Create the window */
695     CreateWindow( p_thread, p_glx, p_vi );
696
697      /* Create an OpenGL context */
698     p_glx->gwctx = gwctx = glXCreateContext( p_display, p_vi, 0, True );
699     if( !gwctx )
700     {
701         msg_Err( p_thread, "Cannot create OpenGL context");
702         XFree( p_vi );
703         return -1;
704     }
705     XFree( p_vi );
706
707     return 0;
708 }
709
710
711 int InitGLX13( vlc_object_t *p_thread, glx_t *p_glx )
712 {
713     Display *p_display;
714     int i_nbelem;
715     GLXFBConfig *p_fbconfs, fbconf;
716     XVisualInfo *p_vi;
717     GLXContext gwctx;
718     int p_attr[] = { GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
719                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, True,
720                      GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0 };
721
722     p_display = p_glx->p_display;
723
724     /* Get the FB configuration */
725     p_fbconfs = glXChooseFBConfig( p_display, 0, p_attr, &i_nbelem );
726     if( (i_nbelem <= 0) || !p_fbconfs )
727     {
728         msg_Err( p_thread, "Cannot get FB configurations");
729         if( p_fbconfs )
730         {
731             XFree( p_fbconfs );
732         }
733         return -1;
734     }
735     fbconf = p_fbconfs[0];
736
737     /* Get the X11 visual */
738     p_vi = glXGetVisualFromFBConfig( p_display, fbconf );
739     if( !p_vi )
740     {
741         msg_Err( p_thread, "Cannot get X11 visual" );
742         XFree( p_fbconfs );
743         return -1;
744     }
745
746     /* Create the window */
747     CreateWindow( p_thread, p_glx, p_vi );
748
749     XFree( p_vi );
750
751     /* Create the GLX window */
752     p_glx->gwnd = glXCreateWindow( p_display, fbconf, p_glx->wnd, NULL );
753     if( p_glx->gwnd == None )
754     {
755         msg_Err( p_thread, "Cannot create GLX window" );
756         return -1;
757     }
758
759     /* Create an OpenGL context */
760     p_glx->gwctx = gwctx = glXCreateNewContext( p_display, fbconf,
761                                                   GLX_RGBA_TYPE, NULL, True );
762     if( !gwctx )
763     {
764         msg_Err( p_thread, "Cannot create OpenGL context");
765         XFree( p_fbconfs );
766         return -1;
767     }
768     XFree( p_fbconfs );
769
770     return 0;
771 }
772
773
774 void CreateWindow( vlc_object_t *p_thread, glx_t *p_glx, XVisualInfo *p_vi )
775 {
776     Display *p_display;
777     XSetWindowAttributes xattr;
778     Window wnd;
779     Colormap cm;
780     XSizeHints* p_size_hints;
781     Atom prop;
782     mwmhints_t mwmhints;
783
784     p_display = p_glx->p_display;
785
786     /* Create a colormap */
787     cm = XCreateColormap( p_display, RootWindow( p_display, p_vi->screen ),
788                           p_vi->visual, AllocNone );
789
790     /* Create the window */
791     xattr.background_pixel = BlackPixel( p_display, DefaultScreen(p_display) );
792     xattr.border_pixel = 0;
793     xattr.colormap = cm;
794     p_glx->wnd = wnd = XCreateWindow( p_display, DefaultRootWindow(p_display),
795             0, 0, p_glx->i_width, p_glx->i_height, 0, p_vi->depth,
796             InputOutput, p_vi->visual,
797             CWBackPixel | CWBorderPixel | CWColormap, &xattr);
798
799     /* Allow the window to be deleted by the window manager */
800     p_glx->wm_delete = XInternAtom( p_display, "WM_DELETE_WINDOW", False );
801     XSetWMProtocols( p_display, wnd, &p_glx->wm_delete, 1 );
802
803     if( p_glx->b_fullscreen )
804     {
805         mwmhints.flags = MWM_HINTS_DECORATIONS;
806         mwmhints.decorations = False;
807
808         prop = XInternAtom( p_display, "_MOTIF_WM_HINTS", False );
809         XChangeProperty( p_display, wnd, prop, prop, 32, PropModeReplace,
810                          (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
811     }
812     else
813     {
814         /* Prevent the window from being resized */
815         p_size_hints = XAllocSizeHints();
816         p_size_hints->flags = PMinSize | PMaxSize;
817         p_size_hints->min_width = p_glx->i_width;
818         p_size_hints->min_height = p_glx->i_height;
819         p_size_hints->max_width = p_glx->i_width;
820         p_size_hints->max_height = p_glx->i_height;
821         XSetWMNormalHints( p_display, wnd, p_size_hints );
822         XFree( p_size_hints );
823     }
824     XSelectInput( p_display, wnd, KeyPressMask );
825 }
826
827
828 void SwitchContext( glx_t *p_glx )
829 {
830     /* Change the current OpenGL context */
831     if( p_glx->b_glx13 )
832     {
833         glXMakeContextCurrent( p_glx->p_display, p_glx->gwnd,
834                                p_glx->gwnd, p_glx->gwctx );
835     }
836     else
837     {
838         glXMakeCurrent( p_glx->p_display, p_glx->wnd,
839                         p_glx->gwctx );
840     }
841 }
842
843
844 int GetAlignedSize( int i_size )
845 {
846     /* Return the nearest power of 2 */
847     int i_result = 1;
848     while( i_result < i_size )
849     {
850         i_result *= 2;
851     }
852     return i_result;
853 }