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 /*****************************************************************************
26 *****************************************************************************/
29 #include <errno.h> /* ENOMEM */
30 #include <stdlib.h> /* free() */
31 #include <string.h> /* strerror() */
43 #include "video_output.h"
46 #include "interface.h"
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
58 /* GGI system informations */
59 ggi_visual_t p_display; /* display device */
61 /* Buffer information */
62 ggi_directbuffer * p_buffer[2]; /* buffers */
63 boolean_t b_must_acquire; /* must be acquired before writing */
66 /*****************************************************************************
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 * );
77 static int GGIOpenDisplay ( vout_thread_t *p_vout );
78 static void GGICloseDisplay( vout_thread_t *p_vout );
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 )
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;
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 )
104 if( TestMethod( VOUT_METHOD_VAR, "ggi" ) )
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 )
121 /* Allocate structure */
122 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
123 if( p_vout->p_sys == NULL )
125 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
129 /* Open and initialize device */
130 if( GGIOpenDisplay( p_vout ) )
132 intf_ErrMsg( "vout error: can't initialize GGI display" );
133 free( p_vout->p_sys );
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 )
146 /* Acquire first buffer */
147 if( p_vout->p_sys->b_must_acquire )
149 ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE );
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 )
163 if( p_vout->p_sys->b_must_acquire )
165 ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
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 )
176 GGICloseDisplay( p_vout );
178 free( p_vout->p_sys );
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 )
189 int i_key; /* unicode key */
191 /* For all events in queue */
192 while( ggiKbhit( p_vout->p_sys->p_display ) )
194 i_key = ggiGetc( p_vout->p_sys->p_display );
198 /* FIXME pass message ! */
199 p_main->p_intf->b_die = 1;
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 )
218 /* Change display frame */
219 if( p_vout->p_sys->b_must_acquire )
221 ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
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 );
227 /* Swap buffers and change write frame */
228 if( p_vout->p_sys->b_must_acquire )
230 ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource,
233 ggiSetWriteFrame( p_vout->p_sys->p_display,
234 p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame );
237 /* following functions are local */
239 /*****************************************************************************
240 * GGIOpenDisplay: open and initialize GGI device
241 *****************************************************************************
242 * Open and initialize display according to preferences specified in the vout
244 *****************************************************************************/
245 static int GGIOpenDisplay( vout_thread_t *p_vout )
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 */
253 /* Initialize library */
256 intf_ErrMsg( "vout error: can't initialize GGI library" );
261 psz_display = main_GetPszVariable( VOUT_DISPLAY_VAR, NULL );
263 p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
265 if( p_vout->p_sys->p_display == NULL )
267 intf_ErrMsg( "vout error: can't open GGI default display" );
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 );
287 /* Check that returned mode has some minimum properties */
291 if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
293 intf_ErrMsg( "vout error: can't set GGI mode" );
294 ggiClose( p_vout->p_sys->p_display );
299 /* Check buffers properties */
300 p_vout->p_sys->b_must_acquire = 0;
301 for( i_index = 0; i_index < 2; i_index++ )
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 )
308 intf_ErrMsg( "vout error: double buffering is not possible" );
309 ggiClose( p_vout->p_sys->p_display );
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) )
321 intf_ErrMsg( "vout error: incorrect video memory type" );
322 ggiClose( p_vout->p_sys->p_display );
327 /* Check if buffer needs to be acquired before write */
328 if( ggiResourceMustAcquire( p_vout->p_sys->p_buffer[ i_index ]->resource ) )
330 p_vout->p_sys->b_must_acquire = 1;
334 if( p_vout->p_sys->b_must_acquire )
336 intf_DbgMsg("buffers must be acquired");
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)) )
348 intf_ErrMsg( "vout error: can't set colors" );
349 ggiClose( p_vout->p_sys->p_display );
354 /* Set clipping for text */
355 if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
356 mode.visible.x, mode.visible.y ) )
358 intf_ErrMsg( "vout error: can't set clipping" );
359 ggiClose( p_vout->p_sys->p_display );
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 ?? */
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 );
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 )
389 /* Restore original mode and close display */
390 ggiClose( p_vout->p_sys->p_display );