]> git.sesse.net Git - vlc/blob - plugins/ggi/vout_ggi.c
* Header cleaning: filled all empty authors fields, added CVS $Id stuff.
[vlc] / plugins / ggi / vout_ggi.c
1 /*****************************************************************************
2  * vout_ggi.c: GGI video output display method
3  *****************************************************************************
4  * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
5  * $Id: vout_ggi.c,v 1.8 2001/03/21 13:42:34 sam Exp $
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.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 #define MODULE_NAME ggi
26 #include "modules_inner.h"
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include "defs.h"
32
33 #include <errno.h>                                                 /* ENOMEM */
34 #include <stdlib.h>                                                /* free() */
35 #include <string.h>                                            /* strerror() */
36
37 #include <ggi/ggi.h>
38
39 #include "config.h"
40 #include "common.h"
41 #include "threads.h"
42 #include "mtime.h"
43 #include "tests.h"
44 #include "modules.h"
45
46 #include "video.h"
47 #include "video_output.h"
48
49 #include "intf_msg.h"
50 #include "interface.h"
51
52 #include "main.h"
53
54 /*****************************************************************************
55  * vout_sys_t: video output GGI method descriptor
56  *****************************************************************************
57  * This structure is part of the video output thread descriptor.
58  * It describes the GGI specific properties of an output thread.
59  *****************************************************************************/
60 typedef struct vout_sys_s
61 {
62     /* GGI system informations */
63     ggi_visual_t        p_display;                         /* display device */
64
65     /* Buffer information */
66     ggi_directbuffer *  p_buffer[2];                              /* buffers */
67     boolean_t           b_must_acquire;   /* must be acquired before writing */
68 } vout_sys_t;
69
70 /*****************************************************************************
71  * Local prototypes.
72  *****************************************************************************/
73 static int  vout_Probe     ( probedata_t *p_data );
74 static int  vout_Create    ( struct vout_thread_s * );
75 static int  vout_Init      ( struct vout_thread_s * );
76 static void vout_End       ( struct vout_thread_s * );
77 static void vout_Destroy   ( struct vout_thread_s * );
78 static int  vout_Manage    ( struct vout_thread_s * );
79 static void vout_Display   ( struct vout_thread_s * );
80
81 static int  GGIOpenDisplay ( vout_thread_t *p_vout );
82 static void GGICloseDisplay( vout_thread_t *p_vout );
83
84 /*****************************************************************************
85  * Functions exported as capabilities. They are declared as static so that
86  * we don't pollute the namespace too much.
87  *****************************************************************************/
88 void _M( vout_getfunctions )( function_list_t * p_function_list )
89 {
90     p_function_list->pf_probe = vout_Probe;
91     p_function_list->functions.vout.pf_create     = vout_Create;
92     p_function_list->functions.vout.pf_init       = vout_Init;
93     p_function_list->functions.vout.pf_end        = vout_End;
94     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
95     p_function_list->functions.vout.pf_manage     = vout_Manage;
96     p_function_list->functions.vout.pf_display    = vout_Display;
97     p_function_list->functions.vout.pf_setpalette = NULL;
98 }
99
100 /*****************************************************************************
101  * vout_Probe: probe the video driver and return a score
102  *****************************************************************************
103  * This function tries to initialize GGI and returns a score to the
104  * plugin manager so that it can select the best plugin.
105  *****************************************************************************/
106 static int vout_Probe( probedata_t *p_data )
107 {
108     if( TestMethod( VOUT_METHOD_VAR, "ggi" ) )
109     {
110         return( 999 );
111     }
112
113     return( 40 );
114 }
115
116 /*****************************************************************************
117  * vout_Create: allocate GGI video thread output method
118  *****************************************************************************
119  * This function allocate and initialize a GGI vout method. It uses some of the
120  * vout properties to choose the correct mode, and change them according to the
121  * mode actually used.
122  *****************************************************************************/
123 int vout_Create( vout_thread_t *p_vout )
124 {
125     /* Allocate structure */
126     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
127     if( p_vout->p_sys == NULL )
128     {
129         intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
130         return( 1 );
131     }
132
133     /* Open and initialize device */
134     if( GGIOpenDisplay( p_vout ) )
135     {
136         intf_ErrMsg( "vout error: can't initialize GGI display" );
137         free( p_vout->p_sys );
138         return( 1 );
139     }
140
141     return( 0 );
142 }
143
144 /*****************************************************************************
145  * vout_Init: initialize GGI video thread output method
146  *****************************************************************************
147  * This function initialize the GGI display device.
148  *****************************************************************************/
149 int vout_Init( vout_thread_t *p_vout )
150 {
151 #define p_b p_vout->p_sys->p_buffer
152     /* Acquire first buffer */
153     if( p_vout->p_sys->b_must_acquire )
154     {
155         ggiResourceAcquire( p_b[ p_vout->i_buffer_index ]->resource,
156                             GGI_ACTYPE_WRITE );
157     }
158
159     /* Listen to the keyboard and the mouse buttons */
160     ggiSetEventMask( p_vout->p_sys->p_display,
161                      emKeyboard | emPtrButtonPress | emPtrButtonRelease );
162
163     /* Set asynchronous display mode -- usually quite faster */
164     ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC );
165
166     return( 0 );
167 #undef p_b
168 }
169
170 /*****************************************************************************
171  * vout_End: terminate GGI video thread output method
172  *****************************************************************************
173  * Terminate an output method created by vout_Create
174  *****************************************************************************/
175 void vout_End( vout_thread_t *p_vout )
176 {
177 #define p_b p_vout->p_sys->p_buffer
178     /* Release buffer */
179     if( p_vout->p_sys->b_must_acquire )
180     {
181         ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
182     }
183 #undef p_b
184 }
185
186 /*****************************************************************************
187  * vout_Destroy: destroy GGI video thread output method
188  *****************************************************************************
189  * Terminate an output method created by vout_Create
190  *****************************************************************************/
191 void vout_Destroy( vout_thread_t *p_vout )
192 {
193     GGICloseDisplay( p_vout );
194
195     free( p_vout->p_sys );
196 }
197
198 /*****************************************************************************
199  * vout_Manage: handle GGI events
200  *****************************************************************************
201  * This function should be called regularly by video output thread. It returns
202  * a non null value if an error occured.
203  *****************************************************************************/
204 int vout_Manage( vout_thread_t *p_vout )
205 {
206     struct timeval tv = { 0, 1000 };                        /* 1 millisecond */
207     gii_event_mask mask;
208     gii_event      event;
209
210     mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease;
211
212     ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
213     
214     while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
215     {
216         ggiEventRead( p_vout->p_sys->p_display, &event, mask);
217
218         switch( event.any.type )
219         {
220             case evKeyRelease:
221
222                 switch( event.key.sym )
223                 {
224                     case 'q':
225                     case 'Q':
226                     case GIIUC_Escape:
227                         /* FIXME pass message ! */
228                         p_main->p_intf->b_die = 1;
229                         break;
230
231                     default:
232                         break;
233                 }
234
235                 break;
236
237             case evPtrButtonRelease:
238
239                 switch( event.pbutton.button )
240                 {
241                     case GII_PBUTTON_RIGHT:
242                         /* FIXME: need locking ! */
243                         p_main->p_intf->b_menu_change = 1;
244                         break;
245                 }
246
247             default:
248         }
249     }
250
251     return( 0 );
252 }
253
254 /*****************************************************************************
255  * vout_Display: displays previously rendered output
256  *****************************************************************************
257  * This function send the currently rendered image to the display, wait until
258  * it is displayed and switch the two rendering buffer, preparing next frame.
259  *****************************************************************************/
260 void vout_Display( vout_thread_t *p_vout )
261 {
262 #define p_b p_vout->p_sys->p_buffer
263     /* Change display frame */
264     if( p_vout->p_sys->b_must_acquire )
265     {
266         ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
267     }
268     ggiSetDisplayFrame( p_vout->p_sys->p_display,
269                         p_b[ p_vout->i_buffer_index ]->frame );
270
271     /* Swap buffers and change write frame */
272     if( p_vout->p_sys->b_must_acquire )
273     {
274         ggiResourceAcquire( p_b[ (p_vout->i_buffer_index + 1) & 1]->resource,
275                             GGI_ACTYPE_WRITE );
276     }
277     ggiSetWriteFrame( p_vout->p_sys->p_display,
278                       p_b[ (p_vout->i_buffer_index + 1) & 1]->frame );
279
280     /* Flush the output so that it actually displays */
281     ggiFlush( p_vout->p_sys->p_display );
282 #undef p_b
283 }
284
285 /* following functions are local */
286
287 /*****************************************************************************
288  * GGIOpenDisplay: open and initialize GGI device
289  *****************************************************************************
290  * Open and initialize display according to preferences specified in the vout
291  * thread fields.
292  *****************************************************************************/
293 static int GGIOpenDisplay( vout_thread_t *p_vout )
294 {
295 #define p_b p_vout->p_sys->p_buffer
296     ggi_mode    mode;                                     /* mode descriptor */
297     ggi_color   col_fg;                                  /* foreground color */
298     ggi_color   col_bg;                                  /* background color */
299     int         i_index;                               /* all purposes index */
300     char        *psz_display;
301
302     /* Initialize library */
303     if( ggiInit() )
304     {
305         intf_ErrMsg( "vout error: can't initialize GGI library" );
306         return( 1 );
307     }
308
309     /* Open display */
310     psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
311
312     p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
313
314     if( p_vout->p_sys->p_display == NULL )
315     {
316         intf_ErrMsg( "vout error: can't open GGI default display" );
317         ggiExit();
318         return( 1 );
319     }
320
321     /* Find most appropriate mode */
322     mode.frames =       2;                                      /* 2 buffers */
323     mode.visible.x =    main_GetIntVariable( VOUT_WIDTH_VAR,
324                                              VOUT_WIDTH_DEFAULT );
325     mode.visible.y =    main_GetIntVariable( VOUT_HEIGHT_VAR,
326                                              VOUT_HEIGHT_DEFAULT );
327     mode.virt.x =       GGI_AUTO;
328     mode.virt.y =       GGI_AUTO;
329     mode.size.x =       GGI_AUTO;
330     mode.size.y =       GGI_AUTO;
331     mode.graphtype =    GT_15BIT;             /* minimum usable screen depth */
332     mode.dpp.x =        GGI_AUTO;
333     mode.dpp.y =        GGI_AUTO;
334     ggiCheckMode( p_vout->p_sys->p_display, &mode );
335
336     /* FIXME: Check that returned mode has some minimum properties */
337
338     /* Set mode */
339     if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
340     {
341         intf_ErrMsg( "vout error: can't set GGI mode" );
342         ggiClose( p_vout->p_sys->p_display );
343         ggiExit();
344         return( 1 );
345     }
346
347     /* Check buffers properties */
348     p_vout->p_sys->b_must_acquire = 0;
349     for( i_index = 0; i_index < 2; i_index++ )
350     {
351         /* Get buffer address */
352         p_vout->p_sys->p_buffer[ i_index ] =
353             (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
354                                                 i_index );
355         if( p_b[ i_index ] == NULL )
356         {
357             intf_ErrMsg( "vout error: double buffering is not possible" );
358             ggiClose( p_vout->p_sys->p_display );
359             ggiExit();
360             return( 1 );
361         }
362
363         /* Check buffer properties */
364         if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB )
365            || ( p_b[ i_index ]->page_size != 0 )
366            || ( p_b[ i_index ]->write == NULL )
367            || ( p_b[ i_index ]->noaccess != 0 )
368            || ( p_b[ i_index ]->align != 0 ) )
369         {
370             intf_ErrMsg( "vout error: incorrect video memory type" );
371             ggiClose( p_vout->p_sys->p_display );
372             ggiExit();
373             return( 1 );
374         }
375
376         /* Check if buffer needs to be acquired before write */
377         if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
378         {
379             p_vout->p_sys->b_must_acquire = 1;
380         }
381     }
382
383     if( p_vout->p_sys->b_must_acquire )
384     {
385         intf_DbgMsg("buffers must be acquired");
386     }
387
388     /* Set graphic context colors */
389     col_fg.r = col_fg.g = col_fg.b = -1;
390     col_bg.r = col_bg.g = col_bg.b = 0;
391     if( ggiSetGCForeground(p_vout->p_sys->p_display,
392                            ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
393         ggiSetGCBackground(p_vout->p_sys->p_display,
394                            ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
395     {
396         intf_ErrMsg( "vout error: can't set colors" );
397         ggiClose( p_vout->p_sys->p_display );
398         ggiExit();
399         return( 1 );
400     }
401
402     /* Set clipping for text */
403     if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
404                          mode.visible.x, mode.visible.y ) )
405     {
406         intf_ErrMsg( "vout error: can't set clipping" );
407         ggiClose( p_vout->p_sys->p_display );
408         ggiExit();
409         return( 1 );
410     }
411
412     /* Set thread information */
413     p_vout->i_width =           mode.visible.x;
414     p_vout->i_height =          mode.visible.y;
415     p_vout->i_bytes_per_line =  p_b[ 0 ]->buffer.plb.stride;
416     p_vout->i_screen_depth =    p_b[ 0 ]->buffer.plb.pixelformat->depth;
417     p_vout->i_bytes_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->size / 8;
418     p_vout->i_red_mask =        p_b[ 0 ]->buffer.plb.pixelformat->red_mask;
419     p_vout->i_green_mask =      p_b[ 0 ]->buffer.plb.pixelformat->green_mask;
420     p_vout->i_blue_mask =       p_b[ 0 ]->buffer.plb.pixelformat->blue_mask;
421
422     /* FIXME: set palette in 8bpp */
423
424     /* Set and initialize buffers */
425     vout_SetBuffers( p_vout, p_b[ 0 ]->write, p_b[ 1 ]->write );
426
427     return( 0 );
428 #undef p_b
429 }
430
431 /*****************************************************************************
432  * GGICloseDisplay: close and reset GGI device
433  *****************************************************************************
434  * This function returns all resources allocated by GGIOpenDisplay and restore
435  * the original state of the device.
436  *****************************************************************************/
437 static void GGICloseDisplay( vout_thread_t *p_vout )
438 {
439     /* Restore original mode and close display */
440     ggiClose( p_vout->p_sys->p_display );
441
442     /* Exit library */
443     ggiExit();
444 }
445