]> git.sesse.net Git - vlc/blob - plugins/ggi/vout_ggi.c
* Ported Glide and MGA plugins to the new module API. MGA never worked,
[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     return( 0 );
140 }
141
142 /*****************************************************************************
143  * vout_Init: initialize GGI video thread output method
144  *****************************************************************************
145  * This function initialize the GGI display device.
146  *****************************************************************************/
147 int vout_Init( vout_thread_t *p_vout )
148 {
149     /* Acquire first buffer */
150     if( p_vout->p_sys->b_must_acquire )
151     {
152         ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE );
153     }
154
155     return( 0 );
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     /* Release buffer */
166     if( p_vout->p_sys->b_must_acquire )
167     {
168         ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
169     }
170 }
171
172 /*****************************************************************************
173  * vout_Destroy: destroy GGI video thread output method
174  *****************************************************************************
175  * Terminate an output method created by vout_Create
176  *****************************************************************************/
177 void vout_Destroy( vout_thread_t *p_vout )
178 {
179     GGICloseDisplay( p_vout );
180
181     free( p_vout->p_sys );
182 }
183
184 /*****************************************************************************
185  * vout_Manage: handle GGI events
186  *****************************************************************************
187  * This function should be called regularly by video output thread. It returns
188  * a non null value if an error occured.
189  *****************************************************************************/
190 int vout_Manage( vout_thread_t *p_vout )
191 {
192     int         i_key;                                        /* unicode key */
193
194     /* For all events in queue */
195     while( ggiKbhit( p_vout->p_sys->p_display ) )
196     {
197         i_key = ggiGetc( p_vout->p_sys->p_display );
198         switch( i_key )
199         {
200         case 'q':
201             /* FIXME pass message ! */
202             p_main->p_intf->b_die = 1;
203             break;
204
205         default:
206             break;
207         }
208     }
209
210     return( 0 );
211 }
212
213 /*****************************************************************************
214  * vout_Display: displays previously rendered output
215  *****************************************************************************
216  * This function send the currently rendered image to the display, wait until
217  * it is displayed and switch the two rendering buffer, preparing next frame.
218  *****************************************************************************/
219 void vout_Display( vout_thread_t *p_vout )
220 {
221     /* Change display frame */
222     if( p_vout->p_sys->b_must_acquire )
223     {
224         ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
225     }
226     ggiFlush( p_vout->p_sys->p_display ); /* XXX?? */
227     ggiSetDisplayFrame( p_vout->p_sys->p_display,
228                         p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->frame );
229
230     /* Swap buffers and change write frame */
231     if( p_vout->p_sys->b_must_acquire )
232     {
233         ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource,
234                             GGI_ACTYPE_WRITE );
235     }
236     ggiSetWriteFrame( p_vout->p_sys->p_display,
237                       p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame );
238 }
239
240 /* following functions are local */
241
242 /*****************************************************************************
243  * GGIOpenDisplay: open and initialize GGI device
244  *****************************************************************************
245  * Open and initialize display according to preferences specified in the vout
246  * thread fields.
247  *****************************************************************************/
248 static int GGIOpenDisplay( vout_thread_t *p_vout )
249 {
250     ggi_mode    mode;                                     /* mode descriptor */
251     ggi_color   col_fg;                                  /* foreground color */
252     ggi_color   col_bg;                                  /* background color */
253     int         i_index;                               /* all purposes index */
254     char        *psz_display;
255
256     /* Initialize library */
257     if( ggiInit() )
258     {
259         intf_ErrMsg( "vout error: can't initialize GGI library" );
260         return( 1 );
261     }
262
263     /* Open display */
264     psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
265
266     p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
267
268     if( p_vout->p_sys->p_display == NULL )
269     {
270         intf_ErrMsg( "vout error: can't open GGI default display" );
271         ggiExit();
272         return( 1 );
273     }
274
275     /* Find most appropriate mode */
276     mode.frames =       2;                                      /* 2 buffers */
277     mode.visible.x =    main_GetIntVariable( VOUT_WIDTH_VAR,
278                                              VOUT_WIDTH_DEFAULT );
279     mode.visible.y =    main_GetIntVariable( VOUT_HEIGHT_VAR,
280                                              VOUT_HEIGHT_DEFAULT );
281     mode.virt.x =       GGI_AUTO;
282     mode.virt.y =       GGI_AUTO;
283     mode.size.x =       GGI_AUTO;
284     mode.size.y =       GGI_AUTO;
285     mode.graphtype =    GT_15BIT;             /* minimum usable screen depth */
286     mode.dpp.x =        GGI_AUTO;
287     mode.dpp.y =        GGI_AUTO;
288     ggiCheckMode( p_vout->p_sys->p_display, &mode );
289
290     /* Check that returned mode has some minimum properties */
291     /* XXX?? */
292
293     /* Set mode */
294     if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
295     {
296         intf_ErrMsg( "vout error: can't set GGI mode" );
297         ggiClose( p_vout->p_sys->p_display );
298         ggiExit();
299         return( 1 );
300     }
301
302     /* Check buffers properties */
303     p_vout->p_sys->b_must_acquire = 0;
304     for( i_index = 0; i_index < 2; i_index++ )
305     {
306         /* Get buffer address */
307         p_vout->p_sys->p_buffer[ i_index ] =
308             (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display, i_index );
309         if( p_vout->p_sys->p_buffer[ i_index ] == NULL )
310         {
311             intf_ErrMsg( "vout error: double buffering is not possible" );
312             ggiClose( p_vout->p_sys->p_display );
313             ggiExit();
314             return( 1 );
315         }
316
317         /* Check buffer properties */
318         if( ! (p_vout->p_sys->p_buffer[ i_index ]->type & GGI_DB_SIMPLE_PLB) ||
319             (p_vout->p_sys->p_buffer[ i_index ]->page_size != 0) ||
320             (p_vout->p_sys->p_buffer[ i_index ]->write == NULL ) ||
321             (p_vout->p_sys->p_buffer[ i_index ]->noaccess != 0) ||
322             (p_vout->p_sys->p_buffer[ i_index ]->align != 0) )
323         {
324             intf_ErrMsg( "vout error: incorrect video memory type" );
325             ggiClose( p_vout->p_sys->p_display );
326             ggiExit();
327             return( 1 );
328         }
329
330         /* Check if buffer needs to be acquired before write */
331         if( ggiResourceMustAcquire( p_vout->p_sys->p_buffer[ i_index ]->resource ) )
332         {
333             p_vout->p_sys->b_must_acquire = 1;
334         }
335     }
336 #ifdef DEBUG
337     if( p_vout->p_sys->b_must_acquire )
338     {
339         intf_DbgMsg("buffers must be acquired");
340     }
341 #endif
342
343     /* Set graphic context colors */
344     col_fg.r = col_fg.g = col_fg.b = -1;
345     col_bg.r = col_bg.g = col_bg.b = 0;
346     if( ggiSetGCForeground(p_vout->p_sys->p_display,
347                            ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
348         ggiSetGCBackground(p_vout->p_sys->p_display,
349                            ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
350     {
351         intf_ErrMsg( "vout error: can't set colors" );
352         ggiClose( p_vout->p_sys->p_display );
353         ggiExit();
354         return( 1 );
355     }
356
357     /* Set clipping for text */
358     if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
359                          mode.visible.x, mode.visible.y ) )
360     {
361         intf_ErrMsg( "vout error: can't set clipping" );
362         ggiClose( p_vout->p_sys->p_display );
363         ggiExit();
364         return( 1 );
365     }
366
367     /* Set thread information */
368     p_vout->i_width =           mode.visible.x;
369     p_vout->i_height =          mode.visible.y;
370     p_vout->i_bytes_per_line =  p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.stride;
371     p_vout->i_screen_depth =    p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->depth;
372     p_vout->i_bytes_per_pixel = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->size / 8;
373     p_vout->i_red_mask =        p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->red_mask;
374     p_vout->i_green_mask =      p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->green_mask;
375     p_vout->i_blue_mask =       p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->blue_mask;
376     /* FIXME: palette in 8bpp ?? */
377
378     /* Set and initialize buffers */
379     vout_SetBuffers( p_vout, p_vout->p_sys->p_buffer[ 0 ]->write, p_vout->p_sys->p_buffer[ 1 ]->write );
380
381     return( 0 );
382 }
383
384 /*****************************************************************************
385  * GGICloseDisplay: close and reset GGI device
386  *****************************************************************************
387  * This function returns all resources allocated by GGIOpenDisplay and restore
388  * the original state of the device.
389  *****************************************************************************/
390 static void GGICloseDisplay( vout_thread_t *p_vout )
391 {
392     /* Restore original mode and close display */
393     ggiClose( p_vout->p_sys->p_display );
394
395     /* Exit library */
396     ggiExit();
397 }
398