1 /*****************************************************************************
2 * vout_ggi.c: GGI video output display method
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000 VideoLAN
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
28 #include <errno.h> /* ENOMEM */
29 #include <stdlib.h> /* free() */
30 #include <string.h> /* strerror() */
41 #include "video_output.h"
45 /*****************************************************************************
46 * vout_sys_t: video output GGI method descriptor
47 *****************************************************************************
48 * This structure is part of the video output thread descriptor.
49 * It describes the GGI specific properties of an output thread.
50 *****************************************************************************/
51 typedef struct vout_sys_s
53 /* GGI system informations */
54 ggi_visual_t p_display; /* display device */
56 /* Buffers informations */
57 ggi_directbuffer * p_buffer[2]; /* buffers */
58 boolean_t b_must_acquire; /* must be acquired before writing */
61 /*****************************************************************************
63 *****************************************************************************/
64 static int GGIOpenDisplay ( vout_thread_t *p_vout, char *psz_display, void *p_data );
65 static void GGICloseDisplay ( vout_thread_t *p_vout );
67 /*****************************************************************************
68 * vout_GGICreate: allocate GGI video thread output method
69 *****************************************************************************
70 * This function allocate and initialize a GGI vout method. It uses some of the
71 * vout properties to choose the correct mode, and change them according to the
73 *****************************************************************************/
74 int vout_GGICreate( vout_thread_t *p_vout, char *psz_display, int i_root_window, void *p_data )
76 /* Allocate structure */
77 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
78 if( p_vout->p_sys == NULL )
80 intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
84 /* Open and initialize device */
85 if( GGIOpenDisplay( p_vout, psz_display, p_data ) )
87 intf_ErrMsg("error: can't initialize GGI display\n");
88 free( p_vout->p_sys );
94 /*****************************************************************************
95 * vout_GGIInit: initialize GGI video thread output method
96 *****************************************************************************
97 * This function initialize the GGI display device.
98 *****************************************************************************/
99 int vout_GGIInit( vout_thread_t *p_vout )
101 /* Acquire first buffer */
102 if( p_vout->p_sys->b_must_acquire )
104 ggiResourceAcquire( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource, GGI_ACTYPE_WRITE );
110 /*****************************************************************************
111 * vout_GGIEnd: terminate Sys video thread output method
112 *****************************************************************************
113 * Terminate an output method created by vout_GGICreate
114 *****************************************************************************/
115 void vout_GGIEnd( vout_thread_t *p_vout )
118 if( p_vout->p_sys->b_must_acquire )
120 ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
124 /*****************************************************************************
125 * vout_GGIDestroy: destroy Sys video thread output method
126 *****************************************************************************
127 * Terminate an output method created by vout_GGICreate
128 *****************************************************************************/
129 void vout_GGIDestroy( vout_thread_t *p_vout )
131 GGICloseDisplay( p_vout );
132 free( p_vout->p_sys );
135 /*****************************************************************************
136 * vout_GGIManage: handle Sys events
137 *****************************************************************************
138 * This function should be called regularly by video output thread. It returns
139 * a non null value if an error occured.
140 *****************************************************************************/
141 int vout_GGIManage( vout_thread_t *p_vout )
143 /* FIXME: 8bpp: change palette ?? */
147 /*****************************************************************************
148 * vout_GGIDisplay: displays previously rendered output
149 *****************************************************************************
150 * This function send the currently rendered image to the display, wait until
151 * it is displayed and switch the two rendering buffer, preparing next frame.
152 *****************************************************************************/
153 void vout_GGIDisplay( vout_thread_t *p_vout )
155 /* Change display frame */
156 if( p_vout->p_sys->b_must_acquire )
158 ggiResourceRelease( p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->resource );
160 ggiFlush( p_vout->p_sys->p_display ); /* XXX?? */
161 ggiSetDisplayFrame( p_vout->p_sys->p_display,
162 p_vout->p_sys->p_buffer[ p_vout->i_buffer_index ]->frame );
164 /* Swap buffers and change write frame */
165 if( p_vout->p_sys->b_must_acquire )
167 ggiResourceAcquire( p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->resource,
170 ggiSetWriteFrame( p_vout->p_sys->p_display,
171 p_vout->p_sys->p_buffer[ (p_vout->i_buffer_index + 1) & 1]->frame );
174 /* following functions are local */
176 /*****************************************************************************
177 * GGIOpenDisplay: open and initialize GGI device
178 *****************************************************************************
179 * Open and initialize display according to preferences specified in the vout
181 *****************************************************************************/
182 static int GGIOpenDisplay( vout_thread_t *p_vout, char *psz_display, void *p_data )
184 ggi_mode mode; /* mode descriptor */
185 ggi_color col_fg; /* foreground color */
186 ggi_color col_bg; /* background color */
187 int i_index; /* all purposes index */
189 /* Initialize library */
192 intf_ErrMsg("error: can't initialize GGI library\n");
197 p_vout->p_sys->p_display = ggiOpen( psz_display, NULL );
198 if( p_vout->p_sys->p_display == NULL )
200 intf_ErrMsg("error: can't open GGI default display\n");
205 /* give the data back to the interface */
206 *(ggi_visual_t *)p_data = p_vout->p_sys->p_display;
208 /* Find most appropriate mode */
209 mode.frames = 2; /* 2 buffers */
210 mode.visible.x = p_vout->i_width; /* minimum width */
211 mode.visible.y = p_vout->i_height; /* minimum height */
212 mode.virt.x = GGI_AUTO;
213 mode.virt.y = GGI_AUTO;
214 mode.size.x = GGI_AUTO;
215 mode.size.y = GGI_AUTO;
216 mode.graphtype = GT_15BIT; /* minimum usable screen depth */
217 mode.dpp.x = GGI_AUTO;
218 mode.dpp.y = GGI_AUTO;
219 ggiCheckMode( p_vout->p_sys->p_display, &mode );
221 /* Check that returned mode has some minimum properties */
225 if( ggiSetMode( p_vout->p_sys->p_display, &mode ) )
227 intf_ErrMsg("error: can't set GGI mode\n");
228 ggiClose( p_vout->p_sys->p_display );
233 /* Check buffers properties */
234 p_vout->p_sys->b_must_acquire = 0;
235 for( i_index = 0; i_index < 2; i_index++ )
237 /* Get buffer address */
238 p_vout->p_sys->p_buffer[ i_index ] =
239 (ggi_directbuffer *)ggiDBGetBuffer( p_vout->p_sys->p_display, i_index );
240 if( p_vout->p_sys->p_buffer[ i_index ] == NULL )
242 intf_ErrMsg("error: double buffering is not possible\n");
243 ggiClose( p_vout->p_sys->p_display );
248 /* Check buffer properties */
249 if( ! (p_vout->p_sys->p_buffer[ i_index ]->type & GGI_DB_SIMPLE_PLB) ||
250 (p_vout->p_sys->p_buffer[ i_index ]->page_size != 0) ||
251 (p_vout->p_sys->p_buffer[ i_index ]->write == NULL ) ||
252 (p_vout->p_sys->p_buffer[ i_index ]->noaccess != 0) ||
253 (p_vout->p_sys->p_buffer[ i_index ]->align != 0) )
255 intf_ErrMsg("error: incorrect video memory type\n");
256 ggiClose( p_vout->p_sys->p_display );
261 /* Check if buffer needs to be acquired before write */
262 if( ggiResourceMustAcquire( p_vout->p_sys->p_buffer[ i_index ]->resource ) )
264 p_vout->p_sys->b_must_acquire = 1;
268 if( p_vout->p_sys->b_must_acquire )
270 intf_DbgMsg("buffers must be acquired\n");
274 /* Set graphic context colors */
275 col_fg.r = col_fg.g = col_fg.b = -1;
276 col_bg.r = col_bg.g = col_bg.b = 0;
277 if( ggiSetGCForeground(p_vout->p_sys->p_display,
278 ggiMapColor(p_vout->p_sys->p_display,&col_fg)) ||
279 ggiSetGCBackground(p_vout->p_sys->p_display,
280 ggiMapColor(p_vout->p_sys->p_display,&col_bg)) )
282 intf_ErrMsg("error: can't set colors\n");
283 ggiClose( p_vout->p_sys->p_display );
288 /* Set clipping for text */
289 if( ggiSetGCClipping(p_vout->p_sys->p_display, 0, 0,
290 mode.visible.x, mode.visible.y ) )
292 intf_ErrMsg("error: can't set clipping\n");
293 ggiClose( p_vout->p_sys->p_display );
298 /* Set thread information */
299 p_vout->i_width = mode.visible.x;
300 p_vout->i_height = mode.visible.y;
301 p_vout->i_bytes_per_line = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.stride;
302 p_vout->i_screen_depth = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->depth;
303 p_vout->i_bytes_per_pixel = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->size / 8;
304 p_vout->i_red_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->red_mask;
305 p_vout->i_green_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->green_mask;
306 p_vout->i_blue_mask = p_vout->p_sys->p_buffer[ 0 ]->buffer.plb.pixelformat->blue_mask;
307 /* FIXME: palette in 8bpp ?? */
309 /* Set and initialize buffers */
310 vout_SetBuffers( p_vout, p_vout->p_sys->p_buffer[ 0 ]->write, p_vout->p_sys->p_buffer[ 1 ]->write );
315 /*****************************************************************************
316 * GGICloseDisplay: close and reset GGI device
317 *****************************************************************************
318 * This function returns all resources allocated by GGIOpenDisplay and restore
319 * the original state of the device.
320 *****************************************************************************/
321 static void GGICloseDisplay( vout_thread_t *p_vout )
323 /* Restore original mode and close display */
324 ggiClose( p_vout->p_sys->p_display );