2 * General Graphics Interface (GGI) vo driver
4 * copyright (C) 2001 Alex Beregszaszi
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.
16 * This file is part of MPlayer.
18 * MPlayer is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * MPlayer is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License along
29 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
30 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
41 #include "video_out.h"
42 #include "video_out_internal.h"
55 static const vo_info_t info
=
57 "General Graphics Interface (GGI) output",
63 const LIBVO_EXTERN(ggi
)
66 static struct ggi_conf_s
{
72 /* source image format */
92 static void window_ontop(void)
94 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] debug: window_ontop() called\n");
95 ggiWmhZOrder(ggi_conf
.vis
, ZO_TOP
);
101 static void set_graphtype(uint32_t format
, ggi_mode
*mode
)
105 mode
->graphtype
= GT_4BIT
;
108 mode
->graphtype
= GT_4BIT
;
109 GT_SETSUBSCHEME(mode
->graphtype
, GT_SUB_HIGHBIT_RIGHT
);
113 mode
->graphtype
= GT_8BIT
;
117 mode
->graphtype
= GT_15BIT
;
121 mode
->graphtype
= GT_16BIT
;
125 mode
->graphtype
= GT_24BIT
;
129 mode
->graphtype
= GT_32BIT
;
136 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
137 uint32_t d_height
, uint32_t flags
, char *title
,
142 {width
, height
}, /* visible */
143 {GGI_AUTO
, GGI_AUTO
}, /* virt */
144 {GGI_AUTO
, GGI_AUTO
}, /* size */
145 GT_AUTO
, /* graphtype */
146 {GGI_AUTO
, GGI_AUTO
} /* dots per pixel */
150 set_graphtype(format
, &mode
);
153 printf("[ggi] mode: ");
158 ggiCheckMode(ggi_conf
.vis
, &mode
);
160 if (ggiSetMode(ggi_conf
.vis
, &mode
) < 0) {
161 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to set display mode\n");
164 if (ggiGetMode(ggi_conf
.vis
, &mode
) < 0) {
165 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to get display mode\n");
168 if ((mode
.graphtype
== GT_INVALID
)
169 || (mode
.graphtype
== GT_AUTO
))
171 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] not supported depth/bpp\n");
176 printf("[ggi] mode: ");
183 ggiWmhSetTitle(ggi_conf
.vis
, title
);
184 if (vo_ontop
) window_ontop();
187 ggiSetFlags(ggi_conf
.vis
, GGIFLAG_ASYNC
);
189 if (GT_SCHEME(mode
.graphtype
) == GT_PALETTE
)
190 ggiSetColorfulPalette(ggi_conf
.vis
);
192 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
195 ggi_conf
.drawvis
= ggiOpen("display-memory", NULL
);
196 if (ggi_conf
.drawvis
== NULL
) {
197 mp_msg(MSGT_VO
, MSGL_ERR
,
198 "[ggi] unable to get backbuffer for conversion\n");
201 memcpy(&drawmode
, &mode
, sizeof(ggi_mode
));
202 drawmode
.graphtype
= GT_32BIT
;
203 drawmode
.size
.x
= GGI_AUTO
;
204 drawmode
.size
.y
= GGI_AUTO
;
205 ggiCheckMode(ggi_conf
.drawvis
, &drawmode
);
206 if (ggiSetMode(ggi_conf
.drawvis
, &drawmode
) < 0) {
207 mp_msg(MSGT_VO
, MSGL_ERR
,
208 "[ggi] unable to set backbuffer mode\n");
211 mode
.graphtype
= drawmode
.graphtype
;
213 ggiSetFlags(ggi_conf
.drawvis
, GGIFLAG_ASYNC
);
215 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
216 vo_screenwidth
= mode
.virt
.x
;
217 vo_screenheight
= mode
.virt
.y
;
221 vo_dbpp
= GT_SIZE(mode
.graphtype
);
224 /* calculate top, left corner */
225 vo_dx
= (vo_screenwidth
- vo_dwidth
) / 2;
226 vo_dy
= (vo_screenheight
- vo_dheight
) / 2;
229 ggi_conf
.srcwidth
= width
;
230 ggi_conf
.srcheight
= height
;
231 ggi_conf
.srcformat
= format
;
233 ggi_conf
.voflags
= flags
;
235 if (IMGFMT_IS_RGB(ggi_conf
.srcformat
)) {
236 ggi_conf
.srcdepth
= IMGFMT_RGB_DEPTH(ggi_conf
.srcformat
);
237 } else if (IMGFMT_IS_BGR(ggi_conf
.srcformat
)) {
238 ggi_conf
.srcdepth
= IMGFMT_BGR_DEPTH(ggi_conf
.srcformat
);
240 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] Unknown image format: %s\n",
241 vo_format_name(ggi_conf
.srcformat
));
245 mp_msg(MSGT_VO
, MSGL_INFO
, "[ggi] input: %dx%dx%d, output: %dx%dx%d\n",
246 ggi_conf
.srcwidth
, ggi_conf
.srcheight
, ggi_conf
.srcdepth
,
247 mode
.virt
.x
, mode
.virt
.y
, vo_dbpp
);
249 ggi_conf
.srcbpp
= (ggi_conf
.srcdepth
+ 7) / 8;
251 ggi_conf
.flushregion
.x1
= vo_dx
;
252 ggi_conf
.flushregion
.y1
= vo_dy
;
253 ggi_conf
.flushregion
.x2
= vo_dwidth
;
254 ggi_conf
.flushregion
.y2
= vo_dheight
;
259 static uint32_t get_image(mp_image_t
*mpi
)
261 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
262 if (!((IMGFMT_IS_BGR(mpi
->imgfmt
)) &&
263 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
268 if (!((IMGFMT_IS_RGB(mpi
->imgfmt
)) &&
269 (IMGFMT_RGB_DEPTH(mpi
->imgfmt
) == vo_dbpp
)))
274 if (!((mpi
->width
== ggi_conf
.srcwidth
) &&
275 (mpi
->height
== ggi_conf
.srcheight
)))
280 mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
281 mpi
->stride
[1] = mpi
->stride
[2] = 0;
283 mpi
->planes
[0] = NULL
;
284 mpi
->stride
[0] = ggi_conf
.srcwidth
* ggi_conf
.srcbpp
;
285 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
288 if (ggi_conf
.voflags
& VOFLAG_FLIPPING
) {
289 mpi
->stride
[0] = -mpi
->stride
[0];
297 static int draw_frame(uint8_t *src
[])
299 ggiPutBox(ggi_conf
.drawvis
, vo_dx
, vo_dy
,
300 vo_dwidth
, vo_dheight
, src
[0]);
302 ggi_conf
.flushregion
.x1
= vo_dx
;
303 ggi_conf
.flushregion
.y1
= vo_dy
;
304 ggi_conf
.flushregion
.x2
= vo_dwidth
;
305 ggi_conf
.flushregion
.y2
= vo_dheight
;
310 static void draw_osd(void)
315 static void flip_page(void)
317 if (ggi_conf
.drawvis
!= ggi_conf
.vis
) {
319 ggiFlushRegion(ggi_conf
.drawvis
,
320 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
321 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
322 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
324 ggiCrossBlit(ggi_conf
.drawvis
,
325 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
326 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
327 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
,
329 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
);
332 ggiFlushRegion(ggi_conf
.vis
,
333 ggi_conf
.flushregion
.x1
, ggi_conf
.flushregion
.y1
,
334 ggi_conf
.flushregion
.x2
- ggi_conf
.flushregion
.x1
,
335 ggi_conf
.flushregion
.y2
- ggi_conf
.flushregion
.y1
);
337 ggi_conf
.flushregion
.x1
= ggi_conf
.flushregion
.x2
= -1;
338 ggi_conf
.flushregion
.y1
= ggi_conf
.flushregion
.y2
= -1;
341 static int draw_slice(uint8_t *src
[], int stride
[],
342 int w
, int h
, int x
, int y
)
344 ggiPutBox(ggi_conf
.drawvis
, vo_dx
+ x
, vo_dy
+ y
, w
, h
, src
[0]);
346 if ((ggi_conf
.flushregion
.x1
== -1) ||
347 ((vo_dx
+ x
) < ggi_conf
.flushregion
.x1
))
349 ggi_conf
.flushregion
.x1
= vo_dx
+ x
;
351 if ((ggi_conf
.flushregion
.y1
== -1) ||
352 ((vo_dy
+ y
) < ggi_conf
.flushregion
.y1
))
354 ggi_conf
.flushregion
.y1
= vo_dy
+ y
;
356 if ((ggi_conf
.flushregion
.x2
== -1) ||
357 ((vo_dx
+ x
+ w
) > ggi_conf
.flushregion
.x2
))
359 ggi_conf
.flushregion
.x2
= vo_dx
+ x
+ w
;
361 if ((ggi_conf
.flushregion
.y2
== -1) ||
362 ((vo_dy
+ y
+ h
) > ggi_conf
.flushregion
.y2
))
364 ggi_conf
.flushregion
.y2
= vo_dy
+ y
+ h
;
370 static int query_format(uint32_t format
)
375 vfcap
= VFCAP_CSP_SUPPORTED
376 | VFCAP_CSP_SUPPORTED_BY_HW
377 | VFCAP_ACCEPT_STRIDE
;
379 if ((!ggi_conf
.depthonscreen
|| !vo_dbpp
) && ggi_conf
.vis
) {
380 if (ggiGetMode(ggi_conf
.vis
, &mode
) == 0) {
381 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
382 vo_dbpp
= GT_SIZE(mode
.graphtype
);
384 if (GT_SCHEME(mode
.graphtype
) == GT_AUTO
) {
385 ggiCheckMode(ggi_conf
.vis
, &mode
);
387 if (GT_SCHEME(mode
.graphtype
) != GT_TRUECOLOR
) {
388 mode
.graphtype
= GT_32BIT
;
389 ggi_conf
.depthonscreen
= GT_DEPTH(mode
.graphtype
);
390 vo_dbpp
= GT_SIZE(mode
.graphtype
);
393 if ((IMGFMT_IS_BGR(format
) && (IMGFMT_BGR_DEPTH(format
) == vo_dbpp
)) ||
394 (IMGFMT_IS_RGB(format
) && (IMGFMT_RGB_DEPTH(format
) == vo_dbpp
)))
398 if (IMGFMT_IS_BGR(format
) || IMGFMT_IS_RGB(format
)) {
399 set_graphtype(format
, &mode
);
401 if (ggiCheckMode(ggi_conf
.drawvis
, &mode
) < 0) {
410 static int preinit(const char *arg
)
412 if (ggiInit() != 0) {
413 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize GGI\n");
417 if (ggiWmhInit() < 0) {
418 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize libggiwmh\n");
425 ggi_conf
.driver
= strdup(arg
);
426 while (ggi_conf
.driver
[i
] != '\0') {
427 if (ggi_conf
.driver
[i
] == '.')
428 ggi_conf
.driver
[i
] = ',';
432 ggi_conf
.driver
= NULL
;
435 ggi_conf
.vis
= ggiOpen(ggi_conf
.driver
);
436 if (ggi_conf
.vis
== NULL
) {
437 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to open '%s' output\n",
438 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
442 ggi_conf
.drawvis
= ggi_conf
.vis
;
446 ggiWmhAttach(ggi_conf
.vis
);
450 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] using '%s' output\n",
451 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
456 static void uninit(void)
459 free(ggi_conf
.driver
);
462 ggiWmhDetach(ggi_conf
.vis
);
466 if (ggi_conf
.drawvis
!= NULL
&& ggi_conf
.drawvis
!= ggi_conf
.vis
)
467 ggiClose(ggi_conf
.drawvis
);
469 ggiClose(ggi_conf
.vis
);
473 static int control(uint32_t request
, void *data
)
476 case VOCTRL_QUERY_FORMAT
:
477 return query_format(*((uint32_t *) data
));
478 case VOCTRL_GET_IMAGE
:
479 return get_image(data
);
482 vo_ontop
= (!(vo_ontop
));
491 #include "osdep/keycodes.h"
493 static void check_events(void)
495 struct timeval tv
= {0, 0};
499 if ((mask
= ggiEventPoll(ggi_conf
.vis
, emAll
, &tv
))) {
500 if (ggiEventRead(ggi_conf
.vis
, &event
, emAll
) != 0) {
501 mp_dbg(MSGT_VO
, MSGL_DBG3
,
502 "type: %4x, origin: %4x, "
503 "sym: %4x, label: %4x, button=%4x\n",
504 event
.any
.origin
, event
.any
.type
, event
.key
.sym
,
505 event
.key
.label
, event
.key
.button
);
507 switch (event
.any
.type
) {
509 switch (event
.key
.sym
) {
510 case GIIK_PAsterisk
: /* PStar */
512 mplayer_put_key('*');
516 mplayer_put_key('/');
520 mplayer_put_key('+');
524 mplayer_put_key('-');
528 mplayer_put_key('o');
532 mplayer_put_key('g');
536 mplayer_put_key('z');
540 mplayer_put_key('x');
544 mplayer_put_key('m');
548 mplayer_put_key('d');
552 mplayer_put_key('q');
556 mplayer_put_key('h');
560 mplayer_put_key('l');
565 mplayer_put_key('p');
568 mplayer_put_key(KEY_UP
);
571 mplayer_put_key(KEY_DOWN
);
574 mplayer_put_key(KEY_LEFT
);
577 mplayer_put_key(KEY_RIGHT
);
580 mplayer_put_key(KEY_PAGE_UP
);
583 mplayer_put_key(KEY_PAGE_DOWN
);