options: fix autoloaded profile handling of flag options
[mplayer/greg.git] / libvo / vo_ggi.c
blobb80e87ed3a85ff25702408e096530fab5a9f0a3a
1 /*
2 * General Graphics Interface (GGI) vo driver
4 * copyright (C) 2001 Alex Beregszaszi
6 * Uses libGGI - http://www.ggi-project.org/
8 * TODO:
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.
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
38 #include "mp_msg.h"
40 #include "config.h"
41 #include "video_out.h"
42 #include "video_out_internal.h"
44 #include "mp_fifo.h"
46 #include <ggi/ggi.h>
48 #ifdef CONFIG_GGIWMH
49 #include <ggi/wmh.h>
50 #endif
52 /* maximum buffers */
53 #undef GGI_FLIP
55 static const vo_info_t info =
57 "General Graphics Interface (GGI) output",
58 "ggi",
59 "Alex Beregszaszi",
60 "major"
63 const LIBVO_EXTERN(ggi)
66 static struct ggi_conf_s {
67 char *driver;
69 ggi_visual_t vis;
70 ggi_visual_t drawvis;
72 /* source image format */
73 int srcwidth;
74 int srcheight;
75 int srcformat;
76 int srcdepth;
77 int srcbpp;
79 /* dirty region */
80 struct {
81 int x1, y1;
82 int x2, y2;
83 } flushregion;
85 int voflags;
87 int depthonscreen;
88 } ggi_conf;
91 #ifdef CONFIG_GGIWMH
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);
96 return;
98 #endif
101 static void set_graphtype(uint32_t format, ggi_mode *mode)
103 switch (format) {
104 case IMGFMT_RGB4:
105 mode->graphtype = GT_4BIT;
106 break;
107 case IMGFMT_BGR4:
108 mode->graphtype = GT_4BIT;
109 GT_SETSUBSCHEME(mode->graphtype, GT_SUB_HIGHBIT_RIGHT);
110 break;
111 case IMGFMT_RGB8:
112 case IMGFMT_BGR8:
113 mode->graphtype = GT_8BIT;
114 break;
115 case IMGFMT_RGB15:
116 case IMGFMT_BGR15:
117 mode->graphtype = GT_15BIT;
118 break;
119 case IMGFMT_RGB16:
120 case IMGFMT_BGR16:
121 mode->graphtype = GT_16BIT;
122 break;
123 case IMGFMT_RGB24:
124 case IMGFMT_BGR24:
125 mode->graphtype = GT_24BIT;
126 break;
127 case IMGFMT_RGB32:
128 case IMGFMT_BGR32:
129 mode->graphtype = GT_32BIT;
130 break;
133 return;
136 static int config(uint32_t width, uint32_t height, uint32_t d_width,
137 uint32_t d_height, uint32_t flags, char *title,
138 uint32_t format)
140 ggi_mode mode = {
141 1, /* frames */
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);
152 #if 0
153 printf("[ggi] mode: ");
154 ggiPrintMode(&mode);
155 printf("\n");
156 #endif
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");
162 return -1;
164 if (ggiGetMode(ggi_conf.vis, &mode) < 0) {
165 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to get display mode\n");
166 return -1;
168 if ((mode.graphtype == GT_INVALID)
169 || (mode.graphtype == GT_AUTO))
171 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] not supported depth/bpp\n");
172 return -1;
175 #if 0
176 printf("[ggi] mode: ");
177 ggiPrintMode(&mode);
178 printf("\n");
179 #endif
182 #ifdef CONFIG_GGIWMH
183 ggiWmhSetTitle(ggi_conf.vis, title);
184 if (vo_ontop) window_ontop();
185 #endif
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) {
193 ggi_mode drawmode;
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");
199 return -1;
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");
209 return -1;
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;
219 vo_dwidth = width;
220 vo_dheight = height;
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);
239 } else {
240 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] Unknown image format: %s\n",
241 vo_format_name(ggi_conf.srcformat));
242 return -1;
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;
256 return 0;
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)))
265 return VO_FALSE;
268 if (!((IMGFMT_IS_RGB(mpi->imgfmt)) &&
269 (IMGFMT_RGB_DEPTH(mpi->imgfmt) == vo_dbpp)))
271 return VO_FALSE;
274 if (!((mpi->width == ggi_conf.srcwidth) &&
275 (mpi->height == ggi_conf.srcheight)))
277 return VO_FALSE;
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;
287 #ifdef GGI_FLIP
288 if (ggi_conf.voflags & VOFLAG_FLIPPING) {
289 mpi->stride[0] = -mpi->stride[0];
291 #endif
293 return VO_TRUE;
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;
307 return 0;
310 static void draw_osd(void)
312 return;
315 static void flip_page(void)
317 if (ggi_conf.drawvis != ggi_conf.vis) {
318 #if 0
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);
323 #endif
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,
328 ggi_conf.vis,
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;
367 return 1;
370 static int query_format(uint32_t format)
372 ggi_mode mode;
373 uint32_t vfcap;
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)))
396 return vfcap;
398 if (IMGFMT_IS_BGR(format) || IMGFMT_IS_RGB(format)) {
399 set_graphtype(format, &mode);
401 if (ggiCheckMode(ggi_conf.drawvis, &mode) < 0) {
402 return 0;
403 } else {
404 return vfcap;
407 return 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");
414 return -1;
416 #ifdef CONFIG_GGIWMH
417 if (ggiWmhInit() < 0) {
418 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to initialize libggiwmh\n");
419 return -1;
421 #endif
423 if (arg) {
424 int i = 0;
425 ggi_conf.driver = strdup(arg);
426 while (ggi_conf.driver[i] != '\0') {
427 if (ggi_conf.driver[i] == '.')
428 ggi_conf.driver[i] = ',';
429 i++;
431 } else {
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);
439 ggiExit();
440 return -1;
442 ggi_conf.drawvis = ggi_conf.vis;
445 #ifdef CONFIG_GGIWMH
446 ggiWmhAttach(ggi_conf.vis);
447 #endif
450 mp_msg(MSGT_VO, MSGL_V, "[ggi] using '%s' output\n",
451 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
453 return 0;
456 static void uninit(void)
458 free(ggi_conf.driver);
460 #ifdef CONFIG_GGIWMH
461 ggiWmhDetach(ggi_conf.vis);
462 ggiWmhExit();
463 #endif
465 if (ggi_conf.drawvis != NULL && ggi_conf.drawvis != ggi_conf.vis)
466 ggiClose(ggi_conf.drawvis);
468 ggiClose(ggi_conf.vis);
469 ggiExit();
472 static int control(uint32_t request, void *data)
474 switch (request) {
475 case VOCTRL_QUERY_FORMAT:
476 return query_format(*((uint32_t *) data));
477 case VOCTRL_GET_IMAGE:
478 return get_image(data);
479 #ifdef CONFIG_GGIWMH
480 case VOCTRL_ONTOP:
481 vo_ontop = (!(vo_ontop));
482 window_ontop();
483 return VO_TRUE;
484 #endif
486 return VO_NOTIMPL;
489 /* EVENT handling */
490 #include "osdep/keycodes.h"
492 static void check_events(void)
494 struct timeval tv = {0, 0};
495 ggi_event event;
496 ggi_event_mask mask;
498 if ((mask = ggiEventPoll(ggi_conf.vis, emAll, &tv))) {
499 if (ggiEventRead(ggi_conf.vis, &event, emAll) != 0) {
500 mp_dbg(MSGT_VO, MSGL_DBG3,
501 "type: %4x, origin: %4x, "
502 "sym: %4x, label: %4x, button=%4x\n",
503 event.any.origin, event.any.type, event.key.sym,
504 event.key.label, event.key.button);
506 switch (event.any.type) {
507 case evKeyPress:
508 switch (event.key.sym) {
509 case GIIK_PAsterisk: /* PStar */
510 case GIIUC_Asterisk:
511 mplayer_put_key('*');
512 break;
513 case GIIK_PSlash:
514 case GIIUC_Slash:
515 mplayer_put_key('/');
516 break;
517 case GIIK_PPlus:
518 case GIIUC_Plus:
519 mplayer_put_key('+');
520 break;
521 case GIIK_PMinus:
522 case GIIUC_Minus:
523 mplayer_put_key('-');
524 break;
525 case GIIUC_o:
526 case GIIUC_O:
527 mplayer_put_key('o');
528 break;
529 case GIIUC_g:
530 case GIIUC_G:
531 mplayer_put_key('g');
532 break;
533 case GIIUC_z:
534 case GIIUC_Z:
535 mplayer_put_key('z');
536 break;
537 case GIIUC_x:
538 case GIIUC_X:
539 mplayer_put_key('x');
540 break;
541 case GIIUC_m:
542 case GIIUC_M:
543 mplayer_put_key('m');
544 break;
545 case GIIUC_d:
546 case GIIUC_D:
547 mplayer_put_key('d');
548 break;
549 case GIIUC_q:
550 case GIIUC_Q:
551 mplayer_put_key('q');
552 break;
553 case GIIUC_h:
554 case GIIUC_H:
555 mplayer_put_key('h');
556 break;
557 case GIIUC_l:
558 case GIIUC_L:
559 mplayer_put_key('l');
560 break;
561 case GIIUC_Space:
562 case GIIUC_p:
563 case GIIUC_P:
564 mplayer_put_key('p');
565 break;
566 case GIIK_Up:
567 mplayer_put_key(KEY_UP);
568 break;
569 case GIIK_Down:
570 mplayer_put_key(KEY_DOWN);
571 break;
572 case GIIK_Left:
573 mplayer_put_key(KEY_LEFT);
574 break;
575 case GIIK_Right:
576 mplayer_put_key(KEY_RIGHT);
577 break;
578 case GIIK_PageUp:
579 mplayer_put_key(KEY_PAGE_UP);
580 break;
581 case GIIK_PageDown:
582 mplayer_put_key(KEY_PAGE_DOWN);
583 break;
584 default:
585 break;
586 } /* switch */
588 break;
589 } /* switch */
590 } /* if */
591 } /* if */
592 return;