2 * Video driver for Nintendo Wii/GameCube Framebuffer device
4 * Copyright (C) 2008 Jing Liu <fatersh-1@yahoo.com>
6 * Maintainer: Benjamin Zores <ben@geexbox.org>
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * This driver handles dedicated ATI GPU, which can be found in:
27 * - Nintendo GameCube (ATI LSI Flipper @ 162 MHz)
28 * - Nintendo Wii (ATI Hollywood @ 243 MHz)
30 * Flipper and Hollywood chipsets are pretty similar, except from clock speed:
31 * - Embedded framebuffer is 2MB.
32 * - Texture cache is 1MB.
33 * - Vertex cache is 0.1 MB.
34 * - Framebuffer is YUY2, not RGB.
35 * - Best resolution is 480p (854x480)
47 #include <sys/ioctl.h>
52 #include "video_out.h"
53 #include "video_out_internal.h"
57 static const vo_info_t info
= {
58 "Nintendo Wii/GameCube Framebuffer Device",
60 "Jing Liu <fartersh-1@yahoo.com>",
66 static signed int pre_init_err
= -2;
68 static char *fb_dev_name
= NULL
;
70 static FILE *vt_fp
= NULL
;
71 static int vt_doit
= 1;
74 static int fb_tty_fd
= -1;
75 static size_t fb_size
;
76 static uint8_t *frame_buffer
;
77 static uint8_t *center
;
78 static struct fb_var_screeninfo fb_orig_vinfo
;
79 static struct fb_var_screeninfo fb_vinfo
;
80 static int fb_pixel_size
; // 32: 4 24: 3 16: 2 15: 2
81 static int fb_line_len
;
85 static int out_height
;
88 static int fb_preinit(int reset
)
90 static int fb_preinit_done
= 0;
91 static int fb_works
= 0;
101 if (!fb_dev_name
&& !(fb_dev_name
= getenv("FRAMEBUFFER")))
102 fb_dev_name
= strdup("/dev/fb0");
103 mp_msg(MSGT_VO
, MSGL_V
, "using %s\n", fb_dev_name
);
105 if ((fb_dev_fd
= open(fb_dev_name
, O_RDWR
)) == -1) {
106 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't open %s: %s\n", fb_dev_name
, strerror(errno
));
109 if (ioctl(fb_dev_fd
, FBIOGET_VSCREENINFO
, &fb_vinfo
)) {
110 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't get VSCREENINFO: %s\n", strerror(errno
));
113 fb_orig_vinfo
= fb_vinfo
;
115 if ((fb_tty_fd
= open("/dev/tty", O_RDWR
)) < 0) {
116 mp_msg(MSGT_VO
, MSGL_ERR
, "notice: Can't open /dev/tty: %s\n", strerror(errno
));
134 static void vt_set_textarea(int u
, int l
)
136 /* how can I determine the font height?
137 * just use 16 for now
139 int urow
= ((u
+ 15) / 16) + 1;
142 mp_msg(MSGT_VO
, MSGL_DBG2
, "vt_set_textarea(%d, %d): %d,%d\n", u
, l
, urow
, lrow
);
145 fprintf(vt_fp
, "\33[%d;%dr\33[%d;%dH", urow
, lrow
, lrow
, 0);
150 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
151 uint32_t d_height
, uint32_t flags
, char *title
,
154 struct fb_fix_screeninfo fb_finfo
;
155 uint32_t black
= 0x00800080;
159 fs
= flags
& VOFLAG_FULLSCREEN
;
161 if (pre_init_err
== -2) {
162 mp_msg(MSGT_VO
, MSGL_ERR
, "Internal fatal error: config() was called before preinit()\n");
172 out_width
= (d_width
&& fs
) ? d_width
: width
;
173 out_height
= (d_width
&& fs
) ? d_height
: height
;
175 fb_vinfo
.xres_virtual
= fb_vinfo
.xres
;
176 fb_vinfo
.yres_virtual
= fb_vinfo
.yres
;
178 if (fb_tty_fd
>= 0 && ioctl(fb_tty_fd
, KDSETMODE
, KD_GRAPHICS
) < 0) {
179 mp_msg(MSGT_VO
, MSGL_V
, "Can't set graphics mode: %s\n", strerror(errno
));
184 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_vinfo
)) {
185 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't put VSCREENINFO: %s\n", strerror(errno
));
186 if (fb_tty_fd
>= 0 && ioctl(fb_tty_fd
, KDSETMODE
, KD_TEXT
) < 0) {
187 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't restore text mode: %s\n", strerror(errno
));
195 out_width
= fb_vinfo
.xres
;
196 out_height
= fb_vinfo
.yres
;
198 if (out_width
< in_width
|| out_height
< in_height
) {
199 mp_msg(MSGT_VO
, MSGL_ERR
, "screensize is smaller than video size\n");
203 if (ioctl(fb_dev_fd
, FBIOGET_FSCREENINFO
, &fb_finfo
)) {
204 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't get FSCREENINFO: %s\n", strerror(errno
));
208 if (fb_finfo
.type
!= FB_TYPE_PACKED_PIXELS
) {
209 mp_msg(MSGT_VO
, MSGL_ERR
, "type %d not supported\n", fb_finfo
.type
);
213 fb_line_len
= fb_finfo
.line_length
;
214 fb_size
= fb_finfo
.smem_len
;
216 frame_buffer
= (uint8_t *) mmap(0, fb_size
, PROT_READ
| PROT_WRITE
,
217 MAP_SHARED
, fb_dev_fd
, 0);
218 if (frame_buffer
== (uint8_t *) -1) {
219 mp_msg(MSGT_VO
, MSGL_ERR
, "Can't mmap %s: %s\n", fb_dev_name
, strerror(errno
));
223 center
= frame_buffer
+
224 ((out_width
- in_width
) / 2) * fb_pixel_size
+
225 ((out_height
- in_height
) / 2) * fb_line_len
;
227 mp_msg(MSGT_VO
, MSGL_DBG2
, "frame_buffer @ %p\n", frame_buffer
);
228 mp_msg(MSGT_VO
, MSGL_DBG2
, "center @ %p\n", center
);
229 mp_msg(MSGT_VO
, MSGL_V
, "pixel per line: %d\n", fb_line_len
/ fb_pixel_size
);
231 /* blanking screen */
232 for (temp
= 0; temp
< fb_size
; temp
+= 4)
233 memcpy(frame_buffer
+ temp
, (void *) &black
, 4);
235 if (vt_doit
&& (vt_fd
= open("/dev/tty", O_WRONLY
)) == -1) {
236 mp_msg(MSGT_VO
, MSGL_ERR
, "can't open /dev/tty: %s\n", strerror(errno
));
239 if (vt_doit
&& !(vt_fp
= fdopen(vt_fd
, "w"))) {
240 mp_msg(MSGT_VO
, MSGL_ERR
, "can't fdopen /dev/tty: %s\n", strerror(errno
));
245 vt_set_textarea((out_height
+ in_height
) / 2, fb_vinfo
.yres
);
250 static int query_format(uint32_t format
)
255 if (format
!= IMGFMT_YUY2
)
258 return VFCAP_ACCEPT_STRIDE
| VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
;
261 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
,
262 unsigned char *srca
, int stride
)
266 dst
= center
+ fb_line_len
* y0
+ fb_pixel_size
* x0
;
268 vo_draw_alpha_yuy2(w
, h
, src
, srca
, stride
, dst
, fb_line_len
);
271 static int draw_frame(uint8_t *src
[])
276 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
280 d
= center
+ fb_line_len
* y
+ fb_pixel_size
* x
;
284 memcpy(d
, s
, w
* fb_pixel_size
);
293 static void check_events(void)
297 static void flip_page(void)
301 static void draw_osd(void)
303 vo_draw_text(in_width
, in_height
, draw_alpha
);
306 static void uninit(void)
308 if (ioctl(fb_dev_fd
, FBIOGET_VSCREENINFO
, &fb_vinfo
))
309 mp_msg(MSGT_VO
, MSGL_WARN
, "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno
));
310 fb_orig_vinfo
.xoffset
= fb_vinfo
.xoffset
;
311 fb_orig_vinfo
.yoffset
= fb_vinfo
.yoffset
;
312 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_orig_vinfo
))
313 mp_msg(MSGT_VO
, MSGL_WARN
, "Can't reset original fb_var_screeninfo: %s\n", strerror(errno
));
314 if (fb_tty_fd
>= 0) {
315 if (ioctl(fb_tty_fd
, KDSETMODE
, KD_TEXT
) < 0)
316 mp_msg(MSGT_VO
, MSGL_WARN
, "Can't restore text mode: %s\n", strerror(errno
));
319 vt_set_textarea(0, fb_orig_vinfo
.yres
);
323 munmap(frame_buffer
, fb_size
);
328 static int preinit(const char *vo_subdevice
)
333 return pre_init_err
= (fb_preinit(0) ? 0 : -1);
337 static uint32_t get_image(mp_image_t
*mpi
)
339 if (((mpi
->type
!= MP_IMGTYPE_STATIC
) && (mpi
->type
!= MP_IMGTYPE_TEMP
)) ||
340 (mpi
->flags
& MP_IMGFLAG_PLANAR
) ||
341 (mpi
->flags
& MP_IMGFLAG_YUV
) ||
342 (mpi
->width
!= in_width
) ||
343 (mpi
->height
!= in_height
)
347 mpi
->planes
[0] = center
;
348 mpi
->stride
[0] = fb_line_len
;
349 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
354 static int control(uint32_t request
, void *data
, ...)
356 if (request
== VOCTRL_GET_IMAGE
)
357 return get_image(data
);
358 else if (request
== VOCTRL_QUERY_FORMAT
)
359 return query_format(*((uint32_t*) data
));