switch_ratio may not work with some filter chains
[mplayer/greg.git] / libvo / vo_ggi.c
blob60a1ad8d9a7d1534a670cd36e72db34c927446ef
1 /*
2 vo_ggi.c - General Graphics Interface (GGI) Renderer for MPlayer
4 (C) Alex Beregszaszi
6 Uses libGGI - http://www.ggi-project.org/
8 TODO:
9 * implement direct rendering support - NEEDS TESTING
10 * implement non-directbuffer support - NEEDS TESTING
11 * check on many devices
12 * implement gamma handling (VAA isn't obsoleted?)
14 BUGS:
15 * palettized playback has bad colors, probably swapped palette?
16 * fbdev & DR produces two downscaled images
17 * fbdev & FLIP (& DR) produces no image
19 Thanks to Andreas Beck for his patches.
21 Many thanks to Atmosfear, he hacked this driver to work with Planar
22 formats, and he fixed the RGB handling.
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
30 #include "mp_msg.h"
32 #include "config.h"
33 #include "video_out.h"
34 #include "video_out_internal.h"
36 #include "fastmemcpy.h"
38 #include <ggi/ggi.h>
40 /* maximum buffers */
41 #define GGI_FRAMES 4
43 #undef GGI_FLIP
45 static vo_info_t info =
47 "General Graphics Interface (GGI) output",
48 "ggi",
49 "Alex Beregszaszi",
50 "under developement"
53 LIBVO_EXTERN (ggi)
55 static struct ggi_conf_s {
56 char *driver;
58 ggi_visual_t vis;
59 ggi_directbuffer *buffer[GGI_FRAMES];
60 ggi_mode gmode;
62 int frames;
63 int currframe;
65 /* source image format */
66 int srcwidth;
67 int srcheight;
68 int srcformat;
69 int srcdepth;
70 int srcbpp;
72 /* destination */
73 int dstwidth;
74 int dstheight;
76 int async;
77 int directbuffer;
79 int voflags;
80 } ggi_conf;
82 static uint32_t draw_frame_directbuffer(uint8_t *src[]);
83 static void draw_osd_directbuffer(void);
84 static void flip_page_directbuffer(void);
86 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width,
87 uint32_t d_height, uint32_t flags, char *title, uint32_t format)
89 ggi_mode mode =
91 GGI_FRAMES, /* frames */
92 { width, height }, /* visible */
93 { GGI_AUTO, GGI_AUTO }, /* virt */
94 { GGI_AUTO, GGI_AUTO }, /* size */
95 GT_AUTO, /* graphtype */
96 { GGI_AUTO, GGI_AUTO } /* dots per pixel */
98 int i;
99 ggi_directbuffer *DB;
101 switch(format)
103 case IMGFMT_RGB|8:
104 case IMGFMT_BGR|8:
105 mode.graphtype = GT_8BIT;
106 break;
107 case IMGFMT_RGB|15:
108 case IMGFMT_BGR|15:
109 mode.graphtype = GT_15BIT;
110 break;
111 case IMGFMT_RGB|16:
112 case IMGFMT_BGR|16:
113 mode.graphtype = GT_16BIT;
114 break;
115 case IMGFMT_RGB|24:
116 case IMGFMT_BGR|24:
117 mode.graphtype = GT_24BIT;
118 break;
119 case IMGFMT_RGB|32:
120 case IMGFMT_BGR|32:
121 mode.graphtype = GT_32BIT;
122 break;
125 #if 0
126 printf("[ggi] mode: ");
127 ggiPrintMode(&mode);
128 printf("\n");
129 #endif
131 ggiCheckMode(ggi_conf.vis, &mode);
133 if (ggiSetMode(ggi_conf.vis, &mode))
135 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to set mode\n");
136 return(-1);
139 if (ggiGetMode(ggi_conf.vis, &mode))
141 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to get mode\n");
142 return(-1);
145 if ((mode.graphtype == GT_INVALID) || (mode.graphtype == GT_AUTO))
147 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] not supported depth/bpp\n");
148 return(-1);
151 ggi_conf.gmode = mode;
153 #if 0
154 printf("[ggi] mode: ");
155 ggiPrintMode(&mode);
156 printf("\n");
157 #endif
159 vo_depthonscreen = GT_DEPTH(mode.graphtype);
160 vo_screenwidth = mode.visible.x;
161 vo_screenheight = mode.visible.y;
163 vo_dx = vo_dy = 0;
164 vo_dwidth = mode.virt.x;
165 vo_dheight = mode.virt.y;
166 vo_dbpp = GT_SIZE(mode.graphtype);
168 ggi_conf.srcwidth = width;
169 ggi_conf.srcheight = height;
170 ggi_conf.srcformat = format;
172 ggi_conf.voflags = flags;
174 if (IMGFMT_IS_RGB(ggi_conf.srcformat))
176 ggi_conf.srcdepth = IMGFMT_RGB_DEPTH(ggi_conf.srcformat);
178 else
179 if (IMGFMT_IS_BGR(ggi_conf.srcformat))
181 ggi_conf.srcdepth = IMGFMT_BGR_DEPTH(ggi_conf.srcformat);
183 else
185 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] Unknown image format: %s\n",
186 vo_format_name(ggi_conf.srcformat));
187 return(-1);
190 vo_dwidth = ggi_conf.dstwidth = ggi_conf.gmode.virt.x;
191 vo_dheight = ggi_conf.dstheight = ggi_conf.gmode.virt.y;
193 ggi_conf.directbuffer = 1;
195 ggi_conf.frames = ggiDBGetNumBuffers(ggi_conf.vis);
196 if (ggi_conf.frames > GGI_FRAMES)
197 ggi_conf.frames = GGI_FRAMES;
199 ggi_conf.currframe = 0;
200 if (!ggi_conf.frames)
202 goto db_err;
205 for (i = 0; i < ggi_conf.frames; i++)
206 ggi_conf.buffer[i] = NULL;
208 /* get available number of buffers */
209 for (i = 0; DB = (ggi_directbuffer *)ggiDBGetBuffer(ggi_conf.vis, i),
210 i < ggi_conf.frames; i++)
212 if (!(DB->type & GGI_DB_SIMPLE_PLB) ||
213 (DB->page_size != 0) ||
214 (DB->write == NULL) ||
215 (DB->noaccess != 0) ||
216 (DB->align != 0) ||
217 (DB->layout != blPixelLinearBuffer))
218 continue;
220 ggi_conf.buffer[DB->frame] = DB;
223 if (ggi_conf.buffer[0] == NULL)
225 goto db_err;
228 for (i = 0; i < ggi_conf.frames; i++)
230 if (ggi_conf.buffer[i] == NULL)
232 ggi_conf.frames = i-1;
233 break;
236 ggiSetDisplayFrame(ggi_conf.vis, ggi_conf.currframe);
237 ggiSetWriteFrame(ggi_conf.vis, ggi_conf.currframe);
239 goto db_ok;
241 db_err:
242 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] direct buffer unavailable, using async mode\n");
243 ggi_conf.directbuffer = 0;
244 ggiSetFlags(ggi_conf.vis, GGIFLAG_ASYNC);
246 db_ok:
247 if (GT_SCHEME(mode.graphtype) == GT_PALETTE)
248 ggiSetColorfulPalette(ggi_conf.vis);
250 if (ggiGetFlags(ggi_conf.vis) & GGIFLAG_ASYNC)
251 ggi_conf.async = 1;
253 mp_msg(MSGT_VO, MSGL_INFO, "[ggi] input: %dx%dx%d, output: %dx%dx%d, frames: %d\n",
254 ggi_conf.srcwidth, ggi_conf.srcheight, ggi_conf.srcdepth,
255 vo_dwidth, vo_dheight, vo_dbpp, ggi_conf.frames);
256 mp_msg(MSGT_VO, MSGL_INFO, "[ggi] directbuffer: %s, async mode: %s\n",
257 ggi_conf.directbuffer ? "yes" : "no",
258 ggi_conf.async ? "yes" : "no");
260 if (ggi_conf.directbuffer)
262 video_out_ggi.draw_frame = draw_frame_directbuffer;
263 video_out_ggi.draw_osd = draw_osd_directbuffer;
264 video_out_ggi.flip_page = flip_page_directbuffer;
267 ggi_conf.srcbpp = (ggi_conf.srcdepth+7)/8;
269 return(0);
272 static uint32_t get_image(mp_image_t *mpi)
274 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
275 if (!ggi_conf.directbuffer ||
276 #if 1
277 (IMGFMT_IS_RGB(mpi->imgfmt) &&
278 (IMGFMT_RGB_DEPTH(mpi->imgfmt) != vo_dbpp)) ||
279 (IMGFMT_IS_BGR(mpi->imgfmt) &&
280 (IMGFMT_BGR_DEPTH(mpi->imgfmt) != vo_dbpp)) ||
281 #else
282 (mpi->imgfmt != ggi_conf.srcformat) ||
283 #endif
284 ((mpi->type != MP_IMGTYPE_STATIC) && (mpi->type != MP_IMGTYPE_TEMP)) ||
285 (mpi->flags & MP_IMGFLAG_PLANAR) ||
286 (mpi->flags & MP_IMGFLAG_YUV) ||
287 (mpi->width != ggi_conf.srcwidth) ||
288 (mpi->height != ggi_conf.srcheight)
290 return(VO_FALSE);
292 if (ggi_conf.frames > 1)
294 mp_msg(MSGT_VO, MSGL_WARN, "[ggi] doublebuffering disabled due to directrendering\n");
295 ggi_conf.currframe = 0;
296 ggi_conf.frames = 1;
299 mpi->planes[1] = mpi->planes[2] = NULL;
300 mpi->stride[1] = mpi->stride[2] = 0;
302 mpi->stride[0] = ggi_conf.srcwidth*ggi_conf.srcbpp;
303 mpi->planes[0] = ggi_conf.buffer[ggi_conf.currframe]->write;
304 mpi->flags |= MP_IMGFLAG_DIRECT;
306 #ifdef GGI_FLIP
307 if (ggi_conf.voflags & VOFLAG_FLIPPING)
309 mpi->stride[0] = -mpi->stride[0];
310 mpi->planes[0] -= mpi->stride[0]*(ggi_conf.srcheight-1);
312 #endif
314 return(VO_TRUE);
317 static uint32_t draw_frame_directbuffer(uint8_t *src[])
319 unsigned char *dst_ptr;
320 int dst_stride, dst_bpp;
322 ggiResourceAcquire(ggi_conf.buffer[ggi_conf.currframe]->resource,
323 GGI_ACTYPE_WRITE);
325 ggiSetWriteFrame(ggi_conf.vis, ggi_conf.currframe);
327 dst_ptr = ggi_conf.buffer[ggi_conf.currframe]->write;
328 dst_stride = ggi_conf.buffer[ggi_conf.currframe]->buffer.plb.stride;
329 dst_bpp = (ggi_conf.buffer[ggi_conf.currframe]->buffer.plb.pixelformat->size+7)/8;
331 #ifdef GGI_FLIP
332 if (ggi_conf.voflags & VOFLAG_FLIPPING)
334 dst_stride = -dst_stride;
335 dst_ptr -= dst_stride*(ggi_conf.srcheight-1);
337 #endif
339 /* memcpy_pic(dst, src, bytes per line, height, dst_stride, src_stride) */
341 memcpy_pic(dst_ptr, src[0], ggi_conf.srcwidth*dst_bpp, ggi_conf.srcheight,
342 dst_stride,
343 ggi_conf.srcwidth*ggi_conf.srcbpp);
345 ggiResourceRelease(ggi_conf.buffer[ggi_conf.currframe]->resource);
347 return(0);
351 static uint32_t draw_frame(uint8_t *src[])
353 ggiPutBox(ggi_conf.vis, 0, 0, ggi_conf.dstwidth, ggi_conf.dstheight, src[0]);
354 ggiFlush(ggi_conf.vis);
356 return(0);
359 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
360 unsigned char *srca, int stride)
362 switch(vo_dbpp)
364 case 32:
365 vo_draw_alpha_rgb32(w, h, src, srca, stride,
366 ggi_conf.buffer[ggi_conf.currframe]->write+4*(ggi_conf.dstwidth*y0+x0), 4*ggi_conf.dstwidth);
367 break;
368 case 24:
369 vo_draw_alpha_rgb24(w, h, src, srca, stride,
370 ggi_conf.buffer[ggi_conf.currframe]->write+3*(ggi_conf.dstwidth*y0+x0), 3*ggi_conf.dstwidth);
371 break;
372 case 16:
373 vo_draw_alpha_rgb16(w, h, src, srca, stride,
374 ggi_conf.buffer[ggi_conf.currframe]->write+2*(ggi_conf.dstwidth*y0+x0), 2*ggi_conf.dstwidth);
375 break;
376 case 15:
377 vo_draw_alpha_rgb15(w, h, src, srca, stride,
378 ggi_conf.buffer[ggi_conf.currframe]->write+2*(ggi_conf.dstwidth*y0+x0), 2*ggi_conf.dstwidth);
379 break;
383 static void draw_osd_directbuffer(void)
385 vo_draw_text(ggi_conf.srcwidth, ggi_conf.srcheight, draw_alpha);
388 static void draw_osd(void)
392 static void flip_page_directbuffer(void)
394 ggiSetDisplayFrame(ggi_conf.vis, ggi_conf.currframe);
395 mp_dbg(MSGT_VO, MSGL_DBG2, "[ggi] flipping, current write frame: %d, display frame: %d\n",
396 ggiGetWriteFrame(ggi_conf.vis), ggiGetDisplayFrame(ggi_conf.vis));
398 ggi_conf.currframe = (ggi_conf.currframe+1) % ggi_conf.frames;
400 if (ggi_conf.async)
401 ggiFlush(ggi_conf.vis);
404 static void flip_page(void)
406 ggiFlush(ggi_conf.vis);
409 static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h,
410 int x, int y)
412 ggiPutHLine(ggi_conf.vis, x, y, w, src[0]);
413 return(1);
416 static uint32_t query_format(uint32_t format)
418 ggi_mode mode;
420 if ((!vo_depthonscreen || !vo_dbpp) && ggi_conf.vis)
422 if (ggiGetMode(ggi_conf.vis, &mode) == 0)
424 vo_depthonscreen = GT_DEPTH(mode.graphtype);
425 vo_dbpp = GT_SIZE(mode.graphtype);
429 if ((IMGFMT_IS_BGR(format) && (IMGFMT_BGR_DEPTH(format) == vo_dbpp)) ||
430 (IMGFMT_IS_RGB(format) && (IMGFMT_RGB_DEPTH(format) == vo_dbpp)))
432 if (ggi_conf.directbuffer)
433 #ifdef GGI_FLIP
434 return(VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|
435 VFCAP_OSD|VFCAP_FLIP);
436 #else
437 return(VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_OSD);
438 #endif
439 else
440 return(VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW);
443 if (IMGFMT_IS_BGR(format) || IMGFMT_IS_RGB(format))
445 switch(format)
447 case IMGFMT_RGB|8:
448 case IMGFMT_BGR|8:
449 mode.graphtype = GT_8BIT;
450 break;
451 case IMGFMT_RGB|15:
452 case IMGFMT_BGR|15:
453 mode.graphtype = GT_15BIT;
454 break;
455 case IMGFMT_RGB|16:
456 case IMGFMT_BGR|16:
457 mode.graphtype = GT_16BIT;
458 break;
459 case IMGFMT_RGB|24:
460 case IMGFMT_BGR|24:
461 mode.graphtype = GT_24BIT;
462 break;
463 case IMGFMT_RGB|32:
464 case IMGFMT_BGR|32:
465 mode.graphtype = GT_32BIT;
466 break;
468 if (ggiCheckMode(ggi_conf.vis, &mode))
470 return 0;
472 else
474 if (ggi_conf.directbuffer)
475 #ifdef GGI_FLIP
476 return(VFCAP_CSP_SUPPORTED|VFCAP_OSD|VFCAP_FLIP);
477 #else
478 return(VFCAP_CSP_SUPPORTED|VFCAP_OSD);
479 #endif
480 else
481 return(VFCAP_CSP_SUPPORTED);
485 return(0);
488 static uint32_t preinit(const char *arg)
490 if (ggiInit() != 0)
492 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to initialize GGI\n");
493 return(-1);
496 if ((char *)arg)
497 ggi_conf.driver = strdup(arg);
498 else
499 ggi_conf.driver = NULL;
501 if ((ggi_conf.vis = ggiOpen(ggi_conf.driver)) == NULL)
503 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to open '%s' output\n",
504 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
505 ggiExit();
506 return(-1);
509 mp_msg(MSGT_VO, MSGL_V, "[ggi] using '%s' output\n",
510 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
512 return 0;
515 static void uninit(void)
517 if (ggi_conf.driver)
518 free(ggi_conf.driver);
519 ggiClose(ggi_conf.vis);
520 ggiExit();
523 static uint32_t control(uint32_t request, void *data, ...)
525 switch(request)
527 case VOCTRL_QUERY_FORMAT:
528 return query_format(*((uint32_t*)data));
529 case VOCTRL_GET_IMAGE:
530 return get_image(data);
532 return VO_NOTIMPL;
535 /* EVENT handling */
536 #include "../osdep/keycodes.h"
537 extern void mplayer_put_key(int code);
539 static void check_events(void)
541 struct timeval tv = {0, 0};
542 ggi_event event;
543 ggi_event_mask mask;
545 if ((mask = ggiEventPoll(ggi_conf.vis, emAll, &tv)))
546 if (ggiEventRead(ggi_conf.vis, &event, emAll) != 0)
548 mp_dbg(MSGT_VO, MSGL_DBG3, "type: %4x, origin: %4x, sym: %4x, label: %4x, button=%4x\n",
549 event.any.origin, event.any.type, event.key.sym, event.key.label, event.key.button);
551 if (event.key.type == evKeyPress)
553 switch(event.key.sym)
555 case GIIK_PAsterisk: /* PStar */
556 case GIIUC_Asterisk:
557 mplayer_put_key('*');
558 break;
559 case GIIK_PSlash:
560 case GIIUC_Slash:
561 mplayer_put_key('/');
562 break;
563 case GIIK_PPlus:
564 case GIIUC_Plus:
565 mplayer_put_key('+');
566 break;
567 case GIIK_PMinus:
568 case GIIUC_Minus:
569 mplayer_put_key('-');
570 break;
571 case GIIUC_o:
572 case GIIUC_O:
573 mplayer_put_key('o');
574 break;
575 case GIIUC_g:
576 case GIIUC_G:
577 mplayer_put_key('g');
578 break;
579 case GIIUC_z:
580 case GIIUC_Z:
581 mplayer_put_key('z');
582 break;
583 case GIIUC_x:
584 case GIIUC_X:
585 mplayer_put_key('x');
586 break;
587 case GIIUC_m:
588 case GIIUC_M:
589 mplayer_put_key('m');
590 break;
591 case GIIUC_d:
592 case GIIUC_D:
593 mplayer_put_key('d');
594 break;
595 case GIIUC_q:
596 case GIIUC_Q:
597 mplayer_put_key('q');
598 break;
599 case GIIUC_h:
600 case GIIUC_H:
601 mplayer_put_key('h');
602 break;
603 case GIIUC_l:
604 case GIIUC_L:
605 mplayer_put_key('l');
606 break;
607 case GIIUC_Space:
608 case GIIUC_p:
609 case GIIUC_P:
610 mplayer_put_key('p');
611 break;
612 case GIIK_Up:
613 mplayer_put_key(KEY_UP);
614 break;
615 case GIIK_Down:
616 mplayer_put_key(KEY_DOWN);
617 break;
618 case GIIK_Left:
619 mplayer_put_key(KEY_LEFT);
620 break;
621 case GIIK_Right:
622 mplayer_put_key(KEY_RIGHT);
623 break;
624 case GIIK_PageUp:
625 mplayer_put_key(KEY_PAGE_UP);
626 break;
627 case GIIK_PageDown:
628 mplayer_put_key(KEY_PAGE_DOWN);
629 break;
630 default:
631 break;
635 return;