* Additional optimizations to the subtitle decoder
[vlc.git] / plugins / ggi / vout_ggi.c
blobb8419c52bd2e4a5d31d7bed14b204bab4e0bb88a
1 /*****************************************************************************
2 * vout_ggi.c: GGI video output display method
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000, 2001 VideoLAN
6 * Authors: Vincent Seguin <seguin@via.ecp.fr>
7 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
24 #define MODULE_NAME ggi
25 #include "modules_inner.h"
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #include "defs.h"
32 #include <errno.h> /* ENOMEM */
33 #include <stdlib.h> /* free() */
34 #include <string.h> /* strerror() */
36 #include <ggi/ggi.h>
38 #include "config.h"
39 #include "common.h"
40 #include "threads.h"
41 #include "mtime.h"
42 #include "tests.h"
43 #include "modules.h"
45 #include "video.h"
46 #include "video_output.h"
48 #include "intf_msg.h"
49 #include "interface.h"
51 #include "main.h"
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
61 /* GGI system informations */
62 ggi_visual_t p_display; /* display device */
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;
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 * );
80 static int GGIOpenDisplay ( vout_thread_t *p_vout );
81 static void GGICloseDisplay( vout_thread_t *p_vout );
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 )
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;
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 )
107 if( TestMethod( VOUT_METHOD_VAR, "ggi" ) )
109 return( 999 );
112 return( 40 );
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 )
124 /* Allocate structure */
125 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
126 if( p_vout->p_sys == NULL )
128 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
129 return( 1 );
132 /* Open and initialize device */
133 if( GGIOpenDisplay( p_vout ) )
135 intf_ErrMsg( "vout error: can't initialize GGI display" );
136 free( p_vout->p_sys );
137 return( 1 );
140 return( 0 );
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 )
150 #define p_b p_vout->p_sys->p_buffer
151 /* Acquire first buffer */
152 if( p_vout->p_sys->b_must_acquire )
154 ggiResourceAcquire( p_b[ p_vout->i_buffer_index ]->resource,
155 GGI_ACTYPE_WRITE );
158 /* Listen to the keyboard and the mouse buttons */
159 ggiSetEventMask( p_vout->p_sys->p_display,
160 emKeyboard | emPtrButtonPress | emPtrButtonRelease );
162 /* Set asynchronous display mode -- usually quite faster */
163 ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC );
165 return( 0 );
166 #undef p_b
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 )
176 #define p_b p_vout->p_sys->p_buffer
177 /* Release buffer */
178 if( p_vout->p_sys->b_must_acquire )
180 ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
182 #undef p_b
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 )
192 GGICloseDisplay( p_vout );
194 free( p_vout->p_sys );
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 )
205 struct timeval tv = { 0, 1000 }; /* 1 millisecond */
206 gii_event_mask mask;
207 gii_event event;
209 mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease;
211 ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
213 while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
215 ggiEventRead( p_vout->p_sys->p_display, &event, mask);
217 switch( event.any.type )
219 case evKeyRelease:
221 switch( event.key.sym )
223 case 'q':
224 case 'Q':
225 case GIIUC_Escape:
226 /* FIXME pass message ! */
227 p_main->p_intf->b_die = 1;
228 break;
230 default:
231 break;
234 break;
236 case evPtrButtonRelease:
238 switch( event.pbutton.button )
240 case GII_PBUTTON_RIGHT:
241 /* FIXME: need locking ! */
242 p_main->p_intf->b_menu_change = 1;
243 break;
246 default:
250 return( 0 );
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 )
261 #define p_b p_vout->p_sys->p_buffer
262 /* Change display frame */
263 if( p_vout->p_sys->b_must_acquire )
265 ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
267 ggiSetDisplayFrame( p_vout->p_sys->p_display,
268 p_b[ p_vout->i_buffer_index ]->frame );
270 /* Swap buffers and change write frame */
271 if( p_vout->p_sys->b_must_acquire )
273 ggiResourceAcquire( p_b[ (p_vout->i_buffer_index + 1) & 1]->resource,
274 GGI_ACTYPE_WRITE );
276 ggiSetWriteFrame( p_vout->p_sys->p_display,
277 p_b[ (p_vout->i_buffer_index + 1) & 1]->frame );
279 /* Flush the output so that it actually displays */
280 ggiFlush( p_vout->p_sys->p_display );
281 #undef p_b
284 /* following functions are local */
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 )
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;
301 /* Initialize library */
302 if( ggiInit() )
304 intf_ErrMsg( "vout error: can't initialize GGI library" );
305 return( 1 );
308 /* Open display */
309 psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
311 p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
313 if( p_vout->p_sys->p_display == NULL )
315 intf_ErrMsg( "vout error: can't open GGI default display" );
316 ggiExit();
317 return( 1 );
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 );
335 /* FIXME: Check that returned mode has some minimum properties */
337 /* Set mode */
338 if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
340 intf_ErrMsg( "vout error: can't set GGI mode" );
341 ggiClose( p_vout->p_sys->p_display );
342 ggiExit();
343 return( 1 );
346 /* Check buffers properties */
347 p_vout->p_sys->b_must_acquire = 0;
348 for( i_index = 0; i_index < 2; i_index++ )
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 )
356 intf_ErrMsg( "vout error: double buffering is not possible" );
357 ggiClose( p_vout->p_sys->p_display );
358 ggiExit();
359 return( 1 );
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 ) )
369 intf_ErrMsg( "vout error: incorrect video memory type" );
370 ggiClose( p_vout->p_sys->p_display );
371 ggiExit();
372 return( 1 );
375 /* Check if buffer needs to be acquired before write */
376 if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
378 p_vout->p_sys->b_must_acquire = 1;
382 if( p_vout->p_sys->b_must_acquire )
384 intf_DbgMsg("buffers must be acquired");
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)) )
395 intf_ErrMsg( "vout error: can't set colors" );
396 ggiClose( p_vout->p_sys->p_display );
397 ggiExit();
398 return( 1 );
401 /* Set clipping for text */
402 if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
403 mode.visible.x, mode.visible.y ) )
405 intf_ErrMsg( "vout error: can't set clipping" );
406 ggiClose( p_vout->p_sys->p_display );
407 ggiExit();
408 return( 1 );
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;
421 /* FIXME: set palette in 8bpp */
423 /* Set and initialize buffers */
424 vout_SetBuffers( p_vout, p_b[ 0 ]->write, p_b[ 1 ]->write );
426 return( 0 );
427 #undef p_b
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 )
438 /* Restore original mode and close display */
439 ggiClose( p_vout->p_sys->p_display );
441 /* Exit library */
442 ggiExit();