Lock/unlock surface only once even when drawing many slices.
[mplayer/glamo.git] / libvo / vo_ggi.c
blob4ff1f40299480ee59d3d1a4f677a07d3d84d51d2
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 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.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
22 #include "mp_msg.h"
24 #include "config.h"
25 #include "video_out.h"
26 #include "video_out_internal.h"
28 #include "mp_fifo.h"
30 #include <ggi/ggi.h>
32 #ifdef CONFIG_GGIWMH
33 #include <ggi/wmh.h>
34 #endif
36 /* maximum buffers */
37 #undef GGI_FLIP
39 static const vo_info_t info =
41 "General Graphics Interface (GGI) output",
42 "ggi",
43 "Alex Beregszaszi",
44 "major"
47 const LIBVO_EXTERN(ggi)
50 static struct ggi_conf_s {
51 char *driver;
53 ggi_visual_t vis;
54 ggi_visual_t drawvis;
56 /* source image format */
57 int srcwidth;
58 int srcheight;
59 int srcformat;
60 int srcdepth;
61 int srcbpp;
63 /* dirty region */
64 struct {
65 int x1, y1;
66 int x2, y2;
67 } flushregion;
69 int voflags;
70 } ggi_conf;
73 #ifdef CONFIG_GGIWMH
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);
78 return;
80 #endif
83 static void set_graphtype(uint32_t format, ggi_mode *mode)
85 switch (format) {
86 case IMGFMT_RGB4:
87 mode->graphtype = GT_4BIT;
88 break;
89 case IMGFMT_BGR4:
90 mode->graphtype = GT_4BIT;
91 GT_SETSUBSCHEME(mode->graphtype, GT_SUB_HIGHBIT_RIGHT);
92 break;
93 case IMGFMT_RGB8:
94 case IMGFMT_BGR8:
95 mode->graphtype = GT_8BIT;
96 break;
97 case IMGFMT_RGB15:
98 case IMGFMT_BGR15:
99 mode->graphtype = GT_15BIT;
100 break;
101 case IMGFMT_RGB16:
102 case IMGFMT_BGR16:
103 mode->graphtype = GT_16BIT;
104 break;
105 case IMGFMT_RGB24:
106 case IMGFMT_BGR24:
107 mode->graphtype = GT_24BIT;
108 break;
109 case IMGFMT_RGB32:
110 case IMGFMT_BGR32:
111 mode->graphtype = GT_32BIT;
112 break;
115 return;
118 static int config(uint32_t width, uint32_t height, uint32_t d_width,
119 uint32_t d_height, uint32_t flags, char *title,
120 uint32_t format)
122 ggi_mode mode = {
123 1, /* frames */
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);
134 #if 0
135 printf("[ggi] mode: ");
136 ggiPrintMode(&mode);
137 printf("\n");
138 #endif
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");
144 return -1;
146 if (ggiGetMode(ggi_conf.vis, &mode) < 0) {
147 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] unable to get display mode\n");
148 return -1;
150 if ((mode.graphtype == GT_INVALID)
151 || (mode.graphtype == GT_AUTO))
153 mp_msg(MSGT_VO, MSGL_ERR, "[ggi] not supported depth/bpp\n");
154 return -1;
157 #if 0
158 printf("[ggi] mode: ");
159 ggiPrintMode(&mode);
160 printf("\n");
161 #endif
164 #ifdef CONFIG_GGIWMH
165 ggiWmhSetTitle(ggi_conf.vis, title);
166 if (vo_ontop) window_ontop();
167 #endif
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) {
175 ggi_mode drawmode;
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");
181 return -1;
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");
191 return -1;
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;
201 vo_dwidth = width;
202 vo_dheight = height;
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);
221 } else {
222 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] Unknown image format: %s\n",
223 vo_format_name(ggi_conf.srcformat));
224 return -1;
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;
238 return 0;
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)))
247 return VO_FALSE;
250 if (!((IMGFMT_IS_RGB(mpi->imgfmt)) &&
251 (IMGFMT_RGB_DEPTH(mpi->imgfmt) == vo_dbpp)))
253 return VO_FALSE;
256 if (!((mpi->width == ggi_conf.srcwidth) &&
257 (mpi->height == ggi_conf.srcheight)))
259 return VO_FALSE;
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;
269 #ifdef GGI_FLIP
270 if (ggi_conf.voflags & VOFLAG_FLIPPING) {
271 mpi->stride[0] = -mpi->stride[0];
273 #endif
275 return VO_TRUE;
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;
289 return 0;
292 static void draw_osd(void)
294 return;
297 static void flip_page(void)
299 if (ggi_conf.drawvis != ggi_conf.vis) {
300 #if 0
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);
305 #endif
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,
310 ggi_conf.vis,
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;
349 return 1;
352 static int query_format(uint32_t format)
354 ggi_mode mode;
355 uint32_t vfcap;
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)))
378 return vfcap;
380 if (IMGFMT_IS_BGR(format) || IMGFMT_IS_RGB(format)) {
381 set_graphtype(format, &mode);
383 if (ggiCheckMode(ggi_conf.drawvis, &mode) < 0) {
384 return 0;
385 } else {
386 return vfcap;
389 return 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");
396 return -1;
398 #ifdef CONFIG_GGIWMH
399 if (ggiWmhInit() < 0) {
400 mp_msg(MSGT_VO, MSGL_FATAL, "[ggi] unable to initialize libggiwmh\n");
401 return -1;
403 #endif
405 if (arg) {
406 int i = 0;
407 ggi_conf.driver = strdup(arg);
408 while (ggi_conf.driver[i] != '\0') {
409 if (ggi_conf.driver[i] == '.')
410 ggi_conf.driver[i] = ',';
411 i++;
413 } else {
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);
421 ggiExit();
422 return -1;
424 ggi_conf.drawvis = ggi_conf.vis;
427 #ifdef CONFIG_GGIWMH
428 ggiWmhAttach(ggi_conf.vis);
429 #endif
432 mp_msg(MSGT_VO, MSGL_V, "[ggi] using '%s' output\n",
433 (ggi_conf.driver == NULL) ? "default" : ggi_conf.driver);
435 return 0;
438 static void uninit(void)
440 if (ggi_conf.driver)
441 free(ggi_conf.driver);
443 #ifdef CONFIG_GGIWMH
444 ggiWmhDetach(ggi_conf.vis);
445 ggiWmhExit();
446 #endif
448 if (ggi_conf.drawvis != NULL && ggi_conf.drawvis != ggi_conf.vis)
449 ggiClose(ggi_conf.drawvis);
451 ggiClose(ggi_conf.vis);
452 ggiExit();
455 static int control(uint32_t request, void *data, ...)
457 switch (request) {
458 case VOCTRL_QUERY_FORMAT:
459 return query_format(*((uint32_t *) data));
460 case VOCTRL_GET_IMAGE:
461 return get_image(data);
462 #ifdef CONFIG_GGIWMH
463 case VOCTRL_ONTOP:
464 vo_ontop = (!(vo_ontop));
465 window_ontop();
466 return VO_TRUE;
467 #endif
469 return VO_NOTIMPL;
472 /* EVENT handling */
473 #include "osdep/keycodes.h"
475 static void check_events(void)
477 struct timeval tv = {0, 0};
478 ggi_event event;
479 ggi_event_mask mask;
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) {
490 case evKeyPress:
491 switch (event.key.sym) {
492 case GIIK_PAsterisk: /* PStar */
493 case GIIUC_Asterisk:
494 mplayer_put_key('*');
495 break;
496 case GIIK_PSlash:
497 case GIIUC_Slash:
498 mplayer_put_key('/');
499 break;
500 case GIIK_PPlus:
501 case GIIUC_Plus:
502 mplayer_put_key('+');
503 break;
504 case GIIK_PMinus:
505 case GIIUC_Minus:
506 mplayer_put_key('-');
507 break;
508 case GIIUC_o:
509 case GIIUC_O:
510 mplayer_put_key('o');
511 break;
512 case GIIUC_g:
513 case GIIUC_G:
514 mplayer_put_key('g');
515 break;
516 case GIIUC_z:
517 case GIIUC_Z:
518 mplayer_put_key('z');
519 break;
520 case GIIUC_x:
521 case GIIUC_X:
522 mplayer_put_key('x');
523 break;
524 case GIIUC_m:
525 case GIIUC_M:
526 mplayer_put_key('m');
527 break;
528 case GIIUC_d:
529 case GIIUC_D:
530 mplayer_put_key('d');
531 break;
532 case GIIUC_q:
533 case GIIUC_Q:
534 mplayer_put_key('q');
535 break;
536 case GIIUC_h:
537 case GIIUC_H:
538 mplayer_put_key('h');
539 break;
540 case GIIUC_l:
541 case GIIUC_L:
542 mplayer_put_key('l');
543 break;
544 case GIIUC_Space:
545 case GIIUC_p:
546 case GIIUC_P:
547 mplayer_put_key('p');
548 break;
549 case GIIK_Up:
550 mplayer_put_key(KEY_UP);
551 break;
552 case GIIK_Down:
553 mplayer_put_key(KEY_DOWN);
554 break;
555 case GIIK_Left:
556 mplayer_put_key(KEY_LEFT);
557 break;
558 case GIIK_Right:
559 mplayer_put_key(KEY_RIGHT);
560 break;
561 case GIIK_PageUp:
562 mplayer_put_key(KEY_PAGE_UP);
563 break;
564 case GIIK_PageDown:
565 mplayer_put_key(KEY_PAGE_DOWN);
566 break;
567 default:
568 break;
569 } /* switch */
571 break;
572 } /* switch */
573 } /* if */
574 } /* if */
575 return;