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 /*****************************************************************************
29 *****************************************************************************/
32 #include <errno.h> /* ENOMEM */
33 #include <stdlib.h> /* free() */
34 #include <string.h> /* strerror() */
46 #include "video_output.h"
49 #include "interface.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 */
69 /*****************************************************************************
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" ) )
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
) );
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
);
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
,
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
);
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
178 if( p_vout
->p_sys
->b_must_acquire
)
180 ggiResourceRelease( p_b
[ p_vout
->i_buffer_index
]->resource
);
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 */
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
)
221 switch( event
.key
.sym
)
226 /* FIXME pass message ! */
227 p_main
->p_intf
->b_die
= 1;
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;
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
,
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
);
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
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 */
301 /* Initialize library */
304 intf_ErrMsg( "vout error: can't initialize GGI library" );
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" );
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 */
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
);
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
,
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
);
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
);
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
);
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
);
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
);
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
);