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