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