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