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