]> git.sesse.net Git - vlc/blob - plugins/ggi/vout_ggi.c
76ea182f1c28cc17227e7096a7e00bbb2626330c
[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.9 2001/04/06 09:15:47 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                 break;
235
236             case evPtrButtonRelease:
237
238                 switch( event.pbutton.button )
239                 {
240                     case GII_PBUTTON_RIGHT:
241                         /* FIXME: need locking ! */
242                         p_main->p_intf->b_menu_change = 1;
243                         break;
244                 }
245                 break;
246
247             default:
248                 break;
249         }
250     }
251
252     return( 0 );
253 }
254
255 /*****************************************************************************
256  * vout_Display: displays previously rendered output
257  *****************************************************************************
258  * This function send the currently rendered image to the display, wait until
259  * it is displayed and switch the two rendering buffer, preparing next frame.
260  *****************************************************************************/
261 void vout_Display( vout_thread_t *p_vout )
262 {
263 #define p_b p_vout->p_sys->p_buffer
264     /* Change display frame */
265     if( p_vout->p_sys->b_must_acquire )
266     {
267         ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
268     }
269     ggiSetDisplayFrame( p_vout->p_sys->p_display,
270                         p_b[ p_vout->i_buffer_index ]->frame );
271
272     /* Swap buffers and change write frame */
273     if( p_vout->p_sys->b_must_acquire )
274     {
275         ggiResourceAcquire( p_b[ (p_vout->i_buffer_index + 1) & 1]->resource,
276                             GGI_ACTYPE_WRITE );
277     }
278     ggiSetWriteFrame( p_vout->p_sys->p_display,
279                       p_b[ (p_vout->i_buffer_index + 1) & 1]->frame );
280
281     /* Flush the output so that it actually displays */
282     ggiFlush( p_vout->p_sys->p_display );
283 #undef p_b
284 }
285
286 /* following functions are local */
287
288 /*****************************************************************************
289  * GGIOpenDisplay: open and initialize GGI device
290  *****************************************************************************
291  * Open and initialize display according to preferences specified in the vout
292  * thread fields.
293  *****************************************************************************/
294 static int GGIOpenDisplay( vout_thread_t *p_vout )
295 {
296 #define p_b p_vout->p_sys->p_buffer
297     ggi_mode    mode;                                     /* mode descriptor */
298     ggi_color   col_fg;                                  /* foreground color */
299     ggi_color   col_bg;                                  /* background color */
300     int         i_index;                               /* all purposes index */
301     char        *psz_display;
302
303     /* Initialize library */
304     if( ggiInit() )
305     {
306         intf_ErrMsg( "vout error: can't initialize GGI library" );
307         return( 1 );
308     }
309
310     /* Open display */
311     psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
312
313     p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
314
315     if( p_vout->p_sys->p_display == NULL )
316     {
317         intf_ErrMsg( "vout error: can't open GGI default display" );
318         ggiExit();
319         return( 1 );
320     }
321
322     /* Find most appropriate mode */
323     mode.frames =       2;                                      /* 2 buffers */
324     mode.visible.x =    main_GetIntVariable( VOUT_WIDTH_VAR,
325                                              VOUT_WIDTH_DEFAULT );
326     mode.visible.y =    main_GetIntVariable( VOUT_HEIGHT_VAR,
327                                              VOUT_HEIGHT_DEFAULT );
328     mode.virt.x =       GGI_AUTO;
329     mode.virt.y =       GGI_AUTO;
330     mode.size.x =       GGI_AUTO;
331     mode.size.y =       GGI_AUTO;
332     mode.graphtype =    GT_15BIT;             /* minimum usable screen depth */
333     mode.dpp.x =        GGI_AUTO;
334     mode.dpp.y =        GGI_AUTO;
335     ggiCheckMode( p_vout->p_sys->p_display, &mode );
336
337     /* FIXME: Check that returned mode has some minimum properties */
338
339     /* Set mode */
340     if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
341     {
342         intf_ErrMsg( "vout error: can't set GGI mode" );
343         ggiClose( p_vout->p_sys->p_display );
344         ggiExit();
345         return( 1 );
346     }
347
348     /* Check buffers properties */
349     p_vout->p_sys->b_must_acquire = 0;
350     for( i_index = 0; i_index < 2; i_index++ )
351     {
352         /* Get buffer address */
353         p_vout->p_sys->p_buffer[ i_index ] =
354             (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
355                                                 i_index );
356         if( p_b[ i_index ] == NULL )
357         {
358             intf_ErrMsg( "vout error: double buffering is not possible" );
359             ggiClose( p_vout->p_sys->p_display );
360             ggiExit();
361             return( 1 );
362         }
363
364         /* Check buffer properties */
365         if( ! ( p_b[ i_index ]->type & GGI_DB_SIMPLE_PLB )
366            || ( p_b[ i_index ]->page_size != 0 )
367            || ( p_b[ i_index ]->write == NULL )
368            || ( p_b[ i_index ]->noaccess != 0 )
369            || ( p_b[ i_index ]->align != 0 ) )
370         {
371             intf_ErrMsg( "vout error: incorrect video memory type" );
372             ggiClose( p_vout->p_sys->p_display );
373             ggiExit();
374             return( 1 );
375         }
376
377         /* Check if buffer needs to be acquired before write */
378         if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
379         {
380             p_vout->p_sys->b_must_acquire = 1;
381         }
382     }
383
384     if( p_vout->p_sys->b_must_acquire )
385     {
386         intf_DbgMsg("buffers must be acquired");
387     }
388
389     /* Set graphic context colors */
390     col_fg.r = col_fg.g = col_fg.b = -1;
391     col_bg.r = col_bg.g = col_bg.b = 0;
392     if( ggiSetGCForeground(p_vout->p_sys->p_display,
393                            ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
394         ggiSetGCBackground(p_vout->p_sys->p_display,
395                            ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
396     {
397         intf_ErrMsg( "vout error: can't set colors" );
398         ggiClose( p_vout->p_sys->p_display );
399         ggiExit();
400         return( 1 );
401     }
402
403     /* Set clipping for text */
404     if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
405                          mode.visible.x, mode.visible.y ) )
406     {
407         intf_ErrMsg( "vout error: can't set clipping" );
408         ggiClose( p_vout->p_sys->p_display );
409         ggiExit();
410         return( 1 );
411     }
412
413     /* Set thread information */
414     p_vout->i_width =           mode.visible.x;
415     p_vout->i_height =          mode.visible.y;
416     p_vout->i_bytes_per_line =  p_b[ 0 ]->buffer.plb.stride;
417     p_vout->i_screen_depth =    p_b[ 0 ]->buffer.plb.pixelformat->depth;
418     p_vout->i_bytes_per_pixel = p_b[ 0 ]->buffer.plb.pixelformat->size / 8;
419     p_vout->i_red_mask =        p_b[ 0 ]->buffer.plb.pixelformat->red_mask;
420     p_vout->i_green_mask =      p_b[ 0 ]->buffer.plb.pixelformat->green_mask;
421     p_vout->i_blue_mask =       p_b[ 0 ]->buffer.plb.pixelformat->blue_mask;
422
423     /* FIXME: set palette in 8bpp */
424
425     /* Set and initialize buffers */
426     vout_SetBuffers( p_vout, p_b[ 0 ]->write, p_b[ 1 ]->write );
427
428     return( 0 );
429 #undef p_b
430 }
431
432 /*****************************************************************************
433  * GGICloseDisplay: close and reset GGI device
434  *****************************************************************************
435  * This function returns all resources allocated by GGIOpenDisplay and restore
436  * the original state of the device.
437  *****************************************************************************/
438 static void GGICloseDisplay( vout_thread_t *p_vout )
439 {
440     /* Restore original mode and close display */
441     ggiClose( p_vout->p_sys->p_display );
442
443     /* Exit library */
444     ggiExit();
445 }
446