2 vo_ggi.c - General Graphics Interface (GGI) Renderer for MPlayer
6 Uses libGGI - http://www.ggi-project.org/
9 * implement gamma handling (VAA isn't obsoleted?)
11 Thanks to Andreas Beck for his patches.
13 Many thanks to Atmosfear, he hacked this driver to work with Planar
14 formats, and he fixed the RGB handling.
25 #include "video_out.h"
26 #include "video_out_internal.h"
39 static const vo_info_t info
=
41 "General Graphics Interface (GGI) output",
47 const LIBVO_EXTERN(ggi
)
50 static struct ggi_conf_s
{
56 /* source image format */
74 static void window_ontop(void)
76 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] debug: window_ontop() called\n");
77 ggiWmhZOrder(ggi_conf
.vis
, ZO_TOP
);
83 static void set_graphtype(uint32_t format
, ggi_mode
*mode
)
87 mode
->graphtype
= GT_4BIT
;
90 mode
->graphtype
= GT_4BIT
;
91 GT_SETSUBSCHEME(mode
->graphtype
, GT_SUB_HIGHBIT_RIGHT
);
95 mode
->graphtype
= GT_8BIT
;
99 mode
->graphtype
= GT_15BIT
;
103 mode
->graphtype
= GT_16BIT
;
107 mode
->graphtype
= GT_24BIT
;
111 mode
->graphtype
= GT_32BIT
;
118 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
119 uint32_t d_height
, uint32_t flags
, char *title
,
124 {width
, height
}, /* visible */
125 {GGI_AUTO
, GGI_AUTO
}, /* virt */
126 {GGI_AUTO
, GGI_AUTO
}, /* size */
127 GT_AUTO
, /* graphtype */
128 {GGI_AUTO
, GGI_AUTO
} /* dots per pixel */
132 set_graphtype(format
, &mode
);
135 printf("[ggi] mode: ");
140 ggiCheckMode(ggi_conf
.vis
, &mode
);
142 if (ggiSetMode(ggi_conf
.vis
, &mode
) < 0) {
143 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to set display mode\n");
146 if (ggiGetMode(ggi_conf
.vis
, &mode
) < 0) {
147 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to get display mode\n");
150 if ((mode
.graphtype
== GT_INVALID
)
151 || (mode
.graphtype
== GT_AUTO
))
153 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] not supported depth/bpp\n");
158 printf("[ggi] mode: ");
165 ggiWmhSetTitle(ggi_conf
.vis
, title
);
166 if (vo_ontop
) window_ontop();
169 ggiSetFlags(ggi_conf
.vis
, GGIFLAG_ASYNC
);
171 if (GT_SCHEME(mode
.graphtype
) == GT_PALETTE
)
172 ggiSetColorfulPalette(ggi_conf
.vis
);
174 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
177 ggi_conf
.drawvis
= ggiOpen("display-memory", NULL
);
178 if (ggi_conf
.drawvis
== NULL
) {
179 mp_msg(MSGT_VO
, MSGL_ERR
,
180 "[ggi] unable to get backbuffer for conversion\n");
183 memcpy(&drawmode
, &mode
, sizeof(ggi_mode
));
184 drawmode
.graphtype
= GT_32BIT
;
185 drawmode
.size
.x
= GGI_AUTO
;
186 drawmode
.size
.y
= GGI_AUTO
;
187 ggiCheckMode(ggi_conf
.drawvis
, &drawmode
);
188 if (ggiSetMode(ggi_conf
.drawvis
, &drawmode
) < 0) {
189 mp_msg(MSGT_VO
, MSGL_ERR
,
190 "[ggi] unable to set backbuffer mode\n");
193 mode
.graphtype
= drawmode
.graphtype
;
195 ggiSetFlags(ggi_conf
.drawvis
, GGIFLAG_ASYNC
);
197 vo_depthonscreen
= GT_DEPTH(mode
.graphtype
);
198 vo_screenwidth
= mode
.virt
.x
;
199 vo_screenheight
= mode
.virt
.y
;
203 vo_dbpp
= GT_SIZE(mode
.graphtype
);
206 /* calculate top, left corner */
207 vo_dx
= (vo_screenwidth
- vo_dwidth
) / 2;
208 vo_dy
= (vo_screenheight
- vo_dheight
) / 2;
211 ggi_conf
.srcwidth
= width
;
212 ggi_conf
.srcheight
= height
;
213 ggi_conf
.srcformat
= format
;
215 ggi_conf
.voflags
= flags
;
217 if (IMGFMT_IS_RGB(ggi_conf
.srcformat
)) {
218 ggi_conf
.srcdepth
= IMGFMT_RGB_DEPTH(ggi_conf
.srcformat
);
219 } else if (IMGFMT_IS_BGR(ggi_conf
.srcformat
)) {
220 ggi_conf
.srcdepth
= IMGFMT_BGR_DEPTH(ggi_conf
.srcformat
);
222 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] Unknown image format: %s\n",
223 vo_format_name(ggi_conf
.srcformat
));
227 mp_msg(MSGT_VO
, MSGL_INFO
, "[ggi] input: %dx%dx%d, output: %dx%dx%d\n",
228 ggi_conf
.srcwidth
, ggi_conf
.srcheight
, ggi_conf
.srcdepth
,
229 mode
.virt
.x
, mode
.virt
.y
, vo_dbpp
);
231 ggi_conf
.srcbpp
= (ggi_conf
.srcdepth
+ 7) / 8;
233 ggi_conf
.flushregion
.x1
= vo_dx
;
234 ggi_conf
.flushregion
.y1
= vo_dy
;
235 ggi_conf
.flushregion
.x2
= vo_dwidth
;
236 ggi_conf
.flushregion
.y2
= vo_dheight
;
241 static uint32_t get_image(mp_image_t
*mpi
)
243 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
244 if (!((IMGFMT_IS_BGR(mpi
->imgfmt
)) &&
245 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
250 if (!((IMGFMT_IS_RGB(mpi
->imgfmt
)) &&
251 (IMGFMT_RGB_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
256 if (!((mpi
->width
== ggi_conf
.srcwidth
) &&
257 (mpi
->height
== ggi_conf
.srcheight
)))
262 mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
263 mpi
->stride
[1] = mpi
->stride
[2] = 0;
265 mpi
->planes
[0] = NULL
;
266 mpi
->stride
[0] = ggi_conf
.srcwidth
* ggi_conf
.srcbpp
;
267 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
270 if (ggi_conf
.voflags
& VOFLAG_FLIPPING
) {
271 mpi
->stride
[0] = -mpi
->stride
[0];
279 static int draw_frame(uint8_t *src
[])
281 ggiPutBox(ggi_conf
.drawvis
, vo_dx
, vo_dy
,
282 vo_dwidth
, vo_dheight
, src
[0]);
284 ggi_conf
.flushregion
.x1
= vo_dx
;
285 ggi_conf
.flushregion
.y1
= vo_dy
;
286 ggi_conf
.flushregion
.x2
= vo_dwidth
;
287 ggi_conf
.flushregion
.y2
= vo_dheight
;
292 static void draw_osd(void)
297 static void flip_page(void)
299 if (ggi_conf
.drawvis
!= ggi_conf
.vis
) {
301 ggiFlushRegion(ggi_conf
.drawvis
,
302 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
303 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
304 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
306 ggiCrossBlit(ggi_conf
.drawvis
,
307 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
308 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
309 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
,
311 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
);
314 ggiFlushRegion(ggi_conf
.vis
,
315 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
316 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
317 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
319 ggi_conf
.flushregion
.x1
= ggi_conf
.flushregion
.x2
= -1;
320 ggi_conf
.flushregion
.y1
= ggi_conf
.flushregion
.y2
= -1;
323 static int draw_slice(uint8_t *src
[], int stride
[],
324 int w
, int h
, int x
, int y
)
326 ggiPutBox(ggi_conf
.drawvis
, vo_dx
+ x
, vo_dy
+ y
, w
, h
, src
[0]);
328 if ((ggi_conf
.flushregion
.x1
== -1) ||
329 ((vo_dx
+ x
) < ggi_conf
.flushregion
.x1
))
331 ggi_conf
.flushregion
.x1
= vo_dx
+ x
;
333 if ((ggi_conf
.flushregion
.y1
== -1) ||
334 ((vo_dy
+ y
) < ggi_conf
.flushregion
.y1
))
336 ggi_conf
.flushregion
.y1
= vo_dy
+ y
;
338 if ((ggi_conf
.flushregion
.x2
== -1) ||
339 ((vo_dx
+ x
+ w
) > ggi_conf
.flushregion
.x2
))
341 ggi_conf
.flushregion
.x2
= vo_dx
+ x
+ w
;
343 if ((ggi_conf
.flushregion
.y2
== -1) ||
344 ((vo_dy
+ y
+ h
) > ggi_conf
.flushregion
.y2
))
346 ggi_conf
.flushregion
.y2
= vo_dy
+ y
+ h
;
352 static int query_format(uint32_t format
)
357 vfcap
= VFCAP_CSP_SUPPORTED
358 | VFCAP_CSP_SUPPORTED_BY_HW
359 | VFCAP_ACCEPT_STRIDE
;
361 if ((!vo_depthonscreen
|| !vo_dbpp
) && ggi_conf
.vis
) {
362 if (ggiGetMode(ggi_conf
.vis
, &mode
) == 0) {
363 vo_depthonscreen
= GT_DEPTH(mode
.graphtype
);
364 vo_dbpp
= GT_SIZE(mode
.graphtype
);
366 if (GT_SCHEME(mode
.graphtype
) == GT_AUTO
) {
367 ggiCheckMode(ggi_conf
.vis
, &mode
);
369 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
370 mode
.graphtype
= GT_32BIT
;
371 vo_depthonscreen
= GT_DEPTH(mode
.graphtype
);
372 vo_dbpp
= GT_SIZE(mode
.graphtype
);
375 if ((IMGFMT_IS_BGR(format
) && (IMGFMT_BGR_DEPTH(format
) == vo_dbpp
)) ||
376 (IMGFMT_IS_RGB(format
) && (IMGFMT_RGB_DEPTH(format
) == vo_dbpp
)))
380 if (IMGFMT_IS_BGR(format
) || IMGFMT_IS_RGB(format
)) {
381 set_graphtype(format
, &mode
);
383 if (ggiCheckMode(ggi_conf
.drawvis
, &mode
) < 0) {
392 static int preinit(const char *arg
)
394 if (ggiInit() != 0) {
395 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize GGI\n");
399 if (ggiWmhInit() < 0) {
400 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize libggiwmh\n");
407 ggi_conf
.driver
= strdup(arg
);
408 while (ggi_conf
.driver
[i
] != '\0') {
409 if (ggi_conf
.driver
[i
] == '.')
410 ggi_conf
.driver
[i
] = ',';
414 ggi_conf
.driver
= NULL
;
417 ggi_conf
.vis
= ggiOpen(ggi_conf
.driver
);
418 if (ggi_conf
.vis
== NULL
) {
419 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to open '%s' output\n",
420 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
424 ggi_conf
.drawvis
= ggi_conf
.vis
;
428 ggiWmhAttach(ggi_conf
.vis
);
432 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] using '%s' output\n",
433 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
438 static void uninit(void)
441 free(ggi_conf
.driver
);
444 ggiWmhDetach(ggi_conf
.vis
);
448 if (ggi_conf
.drawvis
!= NULL
&& ggi_conf
.drawvis
!= ggi_conf
.vis
)
449 ggiClose(ggi_conf
.drawvis
);
451 ggiClose(ggi_conf
.vis
);
455 static int control(uint32_t request
, void *data
, ...)
458 case VOCTRL_QUERY_FORMAT
:
459 return query_format(*((uint32_t *) data
));
460 case VOCTRL_GET_IMAGE
:
461 return get_image(data
);
464 vo_ontop
= (!(vo_ontop
));
473 #include "osdep/keycodes.h"
475 static void check_events(void)
477 struct timeval tv
= {0, 0};
481 if ((mask
= ggiEventPoll(ggi_conf
.vis
, emAll
, &tv
))) {
482 if (ggiEventRead(ggi_conf
.vis
, &event
, emAll
) != 0) {
483 mp_dbg(MSGT_VO
, MSGL_DBG3
,
484 "type: %4x, origin: %4x, "
485 "sym: %4x, label: %4x, button=%4x\n",
486 event
.any
.origin
, event
.any
.type
, event
.key
.sym
,
487 event
.key
.label
, event
.key
.button
);
489 switch (event
.any
.type
) {
491 switch (event
.key
.sym
) {
492 case GIIK_PAsterisk
: /* PStar */
494 mplayer_put_key('*');
498 mplayer_put_key('/');
502 mplayer_put_key('+');
506 mplayer_put_key('-');
510 mplayer_put_key('o');
514 mplayer_put_key('g');
518 mplayer_put_key('z');
522 mplayer_put_key('x');
526 mplayer_put_key('m');
530 mplayer_put_key('d');
534 mplayer_put_key('q');
538 mplayer_put_key('h');
542 mplayer_put_key('l');
547 mplayer_put_key('p');
550 mplayer_put_key(KEY_UP
);
553 mplayer_put_key(KEY_DOWN
);
556 mplayer_put_key(KEY_LEFT
);
559 mplayer_put_key(KEY_RIGHT
);
562 mplayer_put_key(KEY_PAGE_UP
);
565 mplayer_put_key(KEY_PAGE_DOWN
);