2 vo_ggi.c - General Graphics Interface (GGI) Renderer for MPlayer
6 Uses libGGI - http://www.ggi-project.org/
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?)
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.
32 #include "../config.h"
33 #include "video_out.h"
34 #include "video_out_internal.h"
36 #include "fastmemcpy.h"
45 static vo_info_t info
=
47 "General Graphics Interface (GGI) output",
55 static struct ggi_conf_s
{
59 ggi_directbuffer
*buffer
[GGI_FRAMES
];
65 /* source image format */
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
)
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 */
105 mode
.graphtype
= GT_8BIT
;
109 mode
.graphtype
= GT_15BIT
;
113 mode
.graphtype
= GT_16BIT
;
117 mode
.graphtype
= GT_24BIT
;
121 mode
.graphtype
= GT_32BIT
;
126 printf("[ggi] mode: ");
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");
139 if (ggiGetMode(ggi_conf
.vis
, &mode
))
141 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] unable to get mode\n");
145 if ((mode
.graphtype
== GT_INVALID
) || (mode
.graphtype
== GT_AUTO
))
147 mp_msg(MSGT_VO
, MSGL_ERR
, "[ggi] not supported depth/bpp\n");
151 ggi_conf
.gmode
= mode
;
154 printf("[ggi] mode: ");
159 vo_depthonscreen
= GT_DEPTH(mode
.graphtype
);
160 vo_screenwidth
= mode
.visible
.x
;
161 vo_screenheight
= mode
.visible
.y
;
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
);
179 if (IMGFMT_IS_BGR(ggi_conf
.srcformat
))
181 ggi_conf
.srcdepth
= IMGFMT_BGR_DEPTH(ggi_conf
.srcformat
);
185 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] Unknown image format: %s\n",
186 vo_format_name(ggi_conf
.srcformat
));
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
)
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) ||
217 (DB
->layout
!= blPixelLinearBuffer
))
220 ggi_conf
.buffer
[DB
->frame
] = DB
;
223 if (ggi_conf
.buffer
[0] == NULL
)
228 for (i
= 0; i
< ggi_conf
.frames
; i
++)
230 if (ggi_conf
.buffer
[i
] == NULL
)
232 ggi_conf
.frames
= i
-1;
236 ggiSetDisplayFrame(ggi_conf
.vis
, ggi_conf
.currframe
);
237 ggiSetWriteFrame(ggi_conf
.vis
, ggi_conf
.currframe
);
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
);
247 if (GT_SCHEME(mode
.graphtype
) == GT_PALETTE
)
248 ggiSetColorfulPalette(ggi_conf
.vis
);
250 if (ggiGetFlags(ggi_conf
.vis
) & GGIFLAG_ASYNC
)
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;
272 static uint32_t get_image(mp_image_t
*mpi
)
274 /* GGI DirectRendering supports (yet) only BGR/RGB modes */
275 if (!ggi_conf
.directbuffer
||
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
)) ||
282 (mpi
->imgfmt
!= ggi_conf
.srcformat
) ||
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
)
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;
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
;
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);
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
,
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;
332 if (ggi_conf
.voflags
& VOFLAG_FLIPPING
)
334 dst_stride
= -dst_stride
;
335 dst_ptr
-= dst_stride
*(ggi_conf
.srcheight
-1);
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
,
343 ggi_conf
.srcwidth
*ggi_conf
.srcbpp
);
345 ggiResourceRelease(ggi_conf
.buffer
[ggi_conf
.currframe
]->resource
);
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
);
359 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
,
360 unsigned char *srca
, int stride
)
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
);
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
);
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
);
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
);
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
;
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
,
412 ggiPutHLine(ggi_conf
.vis
, x
, y
, w
, src
[0]);
416 static uint32_t query_format(uint32_t format
)
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
)
434 return(VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|
435 VFCAP_OSD
|VFCAP_FLIP
);
437 return(VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_OSD
);
440 return(VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
);
443 if (IMGFMT_IS_BGR(format
) || IMGFMT_IS_RGB(format
))
449 mode
.graphtype
= GT_8BIT
;
453 mode
.graphtype
= GT_15BIT
;
457 mode
.graphtype
= GT_16BIT
;
461 mode
.graphtype
= GT_24BIT
;
465 mode
.graphtype
= GT_32BIT
;
468 if (ggiCheckMode(ggi_conf
.vis
, &mode
))
474 if (ggi_conf
.directbuffer
)
476 return(VFCAP_CSP_SUPPORTED
|VFCAP_OSD
|VFCAP_FLIP
);
478 return(VFCAP_CSP_SUPPORTED
|VFCAP_OSD
);
481 return(VFCAP_CSP_SUPPORTED
);
488 static uint32_t preinit(const char *arg
)
492 mp_msg(MSGT_VO
, MSGL_FATAL
, "[ggi] unable to initialize GGI\n");
497 ggi_conf
.driver
= strdup(arg
);
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
);
509 mp_msg(MSGT_VO
, MSGL_V
, "[ggi] using '%s' output\n",
510 (ggi_conf
.driver
== NULL
) ? "default" : ggi_conf
.driver
);
515 static void uninit(void)
518 free(ggi_conf
.driver
);
519 ggiClose(ggi_conf
.vis
);
523 static uint32_t control(uint32_t request
, void *data
, ...)
527 case VOCTRL_QUERY_FORMAT
:
528 return query_format(*((uint32_t*)data
));
529 case VOCTRL_GET_IMAGE
:
530 return get_image(data
);
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};
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 */
557 mplayer_put_key('*');
561 mplayer_put_key('/');
565 mplayer_put_key('+');
569 mplayer_put_key('-');
573 mplayer_put_key('o');
577 mplayer_put_key('g');
581 mplayer_put_key('z');
585 mplayer_put_key('x');
589 mplayer_put_key('m');
593 mplayer_put_key('d');
597 mplayer_put_key('q');
601 mplayer_put_key('h');
605 mplayer_put_key('l');
610 mplayer_put_key('p');
613 mplayer_put_key(KEY_UP
);
616 mplayer_put_key(KEY_DOWN
);
619 mplayer_put_key(KEY_LEFT
);
622 mplayer_put_key(KEY_RIGHT
);
625 mplayer_put_key(KEY_PAGE_UP
);
628 mplayer_put_key(KEY_PAGE_DOWN
);