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 $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <errno.h> /* ENOMEM */
29 #include <stdlib.h> /* free() */
30 #include <string.h> /* strerror() */
34 #include <videolan/vlc.h>
37 #include "video_output.h"
40 #include "interface.h"
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
50 /* GGI system informations */
51 ggi_visual_t p_display; /* display device */
53 /* Buffer information */
54 ggi_directbuffer * p_buffer[2]; /* buffers */
55 boolean_t b_must_acquire; /* must be acquired before writing */
58 /*****************************************************************************
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 * );
69 static int GGIOpenDisplay ( vout_thread_t *p_vout );
70 static void GGICloseDisplay( vout_thread_t *p_vout );
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 )
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;
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 )
96 if( TestMethod( VOUT_METHOD_VAR, "ggi" ) )
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 )
113 /* Allocate structure */
114 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
115 if( p_vout->p_sys == NULL )
117 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
121 /* Open and initialize device */
122 if( GGIOpenDisplay( p_vout ) )
124 intf_ErrMsg( "vout error: can't initialize GGI display" );
125 free( p_vout->p_sys );
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 )
139 #define p_b p_vout->p_sys->p_buffer
140 /* Acquire first buffer */
141 if( p_vout->p_sys->b_must_acquire )
143 ggiResourceAcquire( p_b[ p_vout->i_buffer_index ]->resource,
147 /* Listen to the keyboard and the mouse buttons */
148 ggiSetEventMask( p_vout->p_sys->p_display,
149 emKeyboard | emPtrButtonPress | emPtrButtonRelease );
151 /* Set asynchronous display mode -- usually quite faster */
152 ggiAddFlags( p_vout->p_sys->p_display, GGIFLAG_ASYNC );
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 )
165 #define p_b p_vout->p_sys->p_buffer
167 if( p_vout->p_sys->b_must_acquire )
169 ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
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 )
181 GGICloseDisplay( p_vout );
183 free( p_vout->p_sys );
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 )
194 struct timeval tv = { 0, 1000 }; /* 1 millisecond */
198 mask = emKeyboard | emPtrButtonPress | emPtrButtonRelease;
200 ggiEventPoll( p_vout->p_sys->p_display, mask, &tv );
202 while( ggiEventsQueued( p_vout->p_sys->p_display, mask) )
204 ggiEventRead( p_vout->p_sys->p_display, &event, mask);
206 switch( event.any.type )
210 switch( event.key.sym )
215 /* FIXME pass message ! */
216 p_main->p_intf->b_die = 1;
224 case evPtrButtonRelease:
226 switch( event.pbutton.button )
228 case GII_PBUTTON_RIGHT:
229 /* FIXME: need locking ! */
230 p_main->p_intf->b_menu_change = 1;
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 )
251 #define p_b p_vout->p_sys->p_buffer
252 /* Change display frame */
253 if( p_vout->p_sys->b_must_acquire )
255 ggiResourceRelease( p_b[ p_vout->i_buffer_index ]->resource );
257 ggiSetDisplayFrame( p_vout->p_sys->p_display,
258 p_b[ p_vout->i_buffer_index ]->frame );
260 /* Swap buffers and change write frame */
261 if( p_vout->p_sys->b_must_acquire )
263 ggiResourceAcquire( p_b[ (p_vout->i_buffer_index + 1) & 1]->resource,
266 ggiSetWriteFrame( p_vout->p_sys->p_display,
267 p_b[ (p_vout->i_buffer_index + 1) & 1]->frame );
269 /* Flush the output so that it actually displays */
270 ggiFlush( p_vout->p_sys->p_display );
274 /* following functions are local */
276 /*****************************************************************************
277 * GGIOpenDisplay: open and initialize GGI device
278 *****************************************************************************
279 * Open and initialize display according to preferences specified in the vout
281 *****************************************************************************/
282 static int GGIOpenDisplay( vout_thread_t *p_vout )
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 */
291 /* Initialize library */
294 intf_ErrMsg( "vout error: can't initialize GGI library" );
299 psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
301 p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
303 if( p_vout->p_sys->p_display == NULL )
305 intf_ErrMsg( "vout error: can't open GGI default display" );
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 );
325 /* FIXME: Check that returned mode has some minimum properties */
328 if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
330 intf_ErrMsg( "vout error: can't set GGI mode" );
331 ggiClose( p_vout->p_sys->p_display );
336 /* Check buffers properties */
337 p_vout->p_sys->b_must_acquire = 0;
338 for( i_index = 0; i_index < 2; i_index++ )
340 /* Get buffer address */
341 p_vout->p_sys->p_buffer[ i_index ] =
342 (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display,
344 if( p_b[ i_index ] == NULL )
346 intf_ErrMsg( "vout error: double buffering is not possible" );
347 ggiClose( p_vout->p_sys->p_display );
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 ) )
359 intf_ErrMsg( "vout error: incorrect video memory type" );
360 ggiClose( p_vout->p_sys->p_display );
365 /* Check if buffer needs to be acquired before write */
366 if( ggiResourceMustAcquire( p_b[ i_index ]->resource ) )
368 p_vout->p_sys->b_must_acquire = 1;
372 if( p_vout->p_sys->b_must_acquire )
374 intf_DbgMsg("buffers must be acquired");
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)) )
385 intf_ErrMsg( "vout error: can't set colors" );
386 ggiClose( p_vout->p_sys->p_display );
391 /* Set clipping for text */
392 if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
393 mode.visible.x, mode.visible.y ) )
395 intf_ErrMsg( "vout error: can't set clipping" );
396 ggiClose( p_vout->p_sys->p_display );
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;
411 /* FIXME: set palette in 8bpp */
413 /* Set and initialize buffers */
414 p_vout->pf_setbuffers( p_vout, p_b[ 0 ]->write, p_b[ 1 ]->write );
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 )
428 /* Restore original mode and close display */
429 ggiClose( p_vout->p_sys->p_display );