2 * copyright (C) 2002 Mark Zealey <mark@zealos.org>
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * 30/03/02: An almost total rewrite, added DR support and support for modes
23 * other than 16bpp. Fixed the crash when playing multiple files
24 * 07/04/02: Fixed DR support, added YUY2 support, fixed OSD stuff.
25 * 08/04/02: Fixed a wierd sound corruption problem caused by some optomizations
27 * 09/04/02: Fixed a problem with changing the variables passed to draw_slice().
28 * Fixed DR support for YV12 et al. Added BGR support. Removed lots of dud code.
29 * 10/04/02: Changed the memcpy functions to mem2agpcpy.. should be a tad
31 * 11/04/02: Added a compile option so you can watch the film with the console
32 * as the background, or not.
33 * 13/04/02: Fix rough OSD stuff by rendering it straight onto the output
34 * buffer. Added double-buffering. Supports hardware zoom/reduce zoom modes.
35 * 13/04/02: Misc cleanups of the code.
36 * 22/10/02: Added geometry support to it
39 * - Use -dr to get direct rendering
40 * - Use -vf yuy2 to get yuy2 rendering, *MUCH* faster than yv12
41 * - To get a black background and nice smooth OSD, use -double
42 * - To get the console as a background, but with scaled OSD, use -nodouble
43 * - The driver supports both scaling and shrinking the image using the -x and
44 * -y options on the mplayer commandline. Also repositioning via the -geometry
53 #include <sys/ioctl.h>
60 #include "fastmemcpy.h"
61 #include "video_out.h"
62 #include "video_out_internal.h"
63 #include "drivers/3dfx.h"
67 static const vo_info_t info
=
69 "3Dfx Banshee/Voodoo3/Voodoo5",
71 "Mark Zealey <mark@zealos.org>",
75 const LIBVO_EXTERN(tdfxfb
)
77 /* Some registers on the card */
78 #define S2S_STRECH_BLT 2 // BLT + Strech
79 #define S2S_IMMED (1 << 8) // Do it immediatly
80 #define S2S_ROP (0xCC << 24) // ???
82 /* Stepping between the different YUV plane registers */
83 #define YUV_STRIDE 1024
91 static struct fb_fix_screeninfo fb_finfo
;
92 static struct fb_var_screeninfo fb_vinfo
;
93 static uint32_t in_width
, in_height
, in_format
, in_depth
, in_voodoo_format
,
94 screenwidth
, screenheight
, screendepth
, vidwidth
, vidheight
, vidx
, vidy
,
95 vid_voodoo_format
, *vidpage
, *hidpage
, *inpage
, vidpageoffset
,
96 hidpageoffset
, inpageoffset
, *memBase0
= NULL
, *memBase1
= NULL
, r_width
, r_height
;
97 static volatile voodoo_io_reg
*reg_IO
;
98 static volatile voodoo_2d_reg
*reg_2d
;
99 static voodoo_yuv_reg
*reg_YUV
;
100 static struct YUV_plane
*YUV
;
101 static void (*alpha_func
)(), (*alpha_func_double
)();
103 static int preinit(const char *arg
)
109 else if(!(name
= getenv("FRAMEBUFFER")))
112 if((fd
= open(name
, O_RDWR
)) == -1) {
113 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Can't open %s: %s.\n", name
, strerror(errno
));
117 if(ioctl(fd
, FBIOGET_FSCREENINFO
, &fb_finfo
)) {
118 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Problem with FBITGET_FSCREENINFO ioctl: %s.\n",
125 if(ioctl(fd
, FBIOGET_VSCREENINFO
, &fb_vinfo
)) {
126 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Problem with FBITGET_VSCREENINFO ioctl: %s.\n",
133 /* BANSHEE means any of the series aparently */
134 if (fb_finfo
.accel
!= FB_ACCEL_3DFX_BANSHEE
) {
135 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] This driver only supports the 3Dfx Banshee, Voodoo3 and Voodoo 5.\n");
141 // Check the depth now as config() musn't fail
142 switch(fb_vinfo
.bits_per_pixel
) {
148 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] %d bpp output is not supported.\n", fb_vinfo
.bits_per_pixel
);
154 /* Open up a window to the hardware */
155 memBase1
= mmap(0, fb_finfo
.smem_len
, PROT_READ
| PROT_WRITE
,
157 memBase0
= mmap(0, fb_finfo
.mmio_len
, PROT_READ
| PROT_WRITE
,
158 MAP_SHARED
, fd
, fb_finfo
.smem_len
);
160 if((long)memBase0
== -1 || (long)memBase1
== -1) {
161 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Couldn't map memory areas: %s.\n", strerror(errno
));
162 if((long)memBase0
!= -1)
163 munmap(memBase0
, fb_finfo
.smem_len
);
164 if((long)memBase1
!= -1)
165 munmap(memBase1
, fb_finfo
.smem_len
);
166 memBase0
= memBase1
= NULL
;
170 /* Set up global pointers to the voodoo's regs */
171 reg_IO
= (void *)memBase0
+ VOODOO_IO_REG_OFFSET
;
172 reg_2d
= (void *)memBase0
+ VOODOO_2D_REG_OFFSET
;
173 reg_YUV
= (void *)memBase0
+ VOODOO_YUV_REG_OFFSET
;
174 YUV
= (void *)memBase0
+ VOODOO_YUV_PLANE_OFFSET
;
179 static void uninit(void)
182 /* Restore the screen (Linux lives at 0) */
183 reg_IO
->vidDesktopStartAddr
= 0;
187 /* And close our mess */
189 munmap(memBase1
, fb_finfo
.smem_len
);
194 munmap(memBase0
, fb_finfo
.mmio_len
);
204 static void clear_screen(void)
206 /* There needs to be some sort of delay here or else things seriously
207 * screw up. Causes the image to not be the right size on screen if
208 * this isn't like this. A printf before the memset call also seems to
209 * work, but this made more sense since it actually checks the status of
212 if(vo_doublebuffering
) {
213 /* first wait for the card to be ready, do not try to write
214 * every time - alex */
215 do {} while((reg_IO
->status
& 0x1f) < 1);
216 memset(vidpage
, 0, screenwidth
* screenheight
* screendepth
);
217 memset(hidpage
, 0, screenwidth
* screenheight
* screendepth
);
221 /* Setup output screen dimensions etc */
222 static void setup_screen(uint32_t full
)
224 aspect(&vidwidth
, &vidheight
, full
? A_ZOOM
: A_NOZOOM
);
226 geometry(&vidx
, &vidy
, &vidwidth
, &vidheight
, screenwidth
, screenheight
);
231 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
,
232 uint32_t flags
, char *title
, uint32_t format
)
234 screenwidth
= fb_vinfo
.xres
;
235 screenheight
= fb_vinfo
.yres
;
236 aspect_save_screenres(fb_vinfo
.xres
,fb_vinfo
.yres
);
241 aspect_save_orig(width
,height
);
245 aspect_save_prescale(d_width
,d_height
);
247 /* Setup the screen for rendering to */
248 switch(fb_vinfo
.bits_per_pixel
) {
251 vid_voodoo_format
= VOODOO_BLT_FORMAT_16
;
252 alpha_func_double
= vo_draw_alpha_rgb16
;
257 vid_voodoo_format
= VOODOO_BLT_FORMAT_24
;
258 alpha_func_double
= vo_draw_alpha_rgb24
;
263 vid_voodoo_format
= VOODOO_BLT_FORMAT_32
;
264 alpha_func_double
= vo_draw_alpha_rgb32
;
268 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[VO_TDFXFB] %d bpp output is not supported (This should never have happened).\n", fb_vinfo
.bits_per_pixel
);
272 vid_voodoo_format
|= screenwidth
* screendepth
;
274 /* Some defaults here */
275 in_voodoo_format
= VOODOO_BLT_FORMAT_YUYV
;
277 alpha_func
= vo_draw_alpha_yuy2
;
286 in_voodoo_format
= VOODOO_BLT_FORMAT_UYVY
;
289 in_voodoo_format
= VOODOO_BLT_FORMAT_16
;
290 alpha_func
= vo_draw_alpha_rgb16
;
295 in_voodoo_format
= VOODOO_BLT_FORMAT_24
;
296 alpha_func
= vo_draw_alpha_rgb24
;
301 in_voodoo_format
= VOODOO_BLT_FORMAT_32
;
302 alpha_func
= vo_draw_alpha_rgb32
;
306 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Eik! Something's wrong with control().\n");
310 in_voodoo_format
|= in_width
* in_depth
;
312 /* Linux lives in the first frame */
313 if(vo_doublebuffering
) {
314 vidpageoffset
= screenwidth
* screenheight
* screendepth
;
315 hidpageoffset
= vidpageoffset
+ screenwidth
* screenheight
* screendepth
;
317 vidpageoffset
= hidpageoffset
= 0; /* Console background */
320 inpageoffset
= hidpageoffset
+ screenwidth
* screenheight
* screendepth
;
322 if(inpageoffset
+ in_width
* in_depth
* in_height
> fb_finfo
.smem_len
) {
323 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_TDFXFB] Not enough video memory to play this movie. Try at a lower resolution.\n");
327 vidpage
= (void *)memBase1
+ (unsigned long)vidpageoffset
;
328 hidpage
= (void *)memBase1
+ (unsigned long)hidpageoffset
;
329 inpage
= (void *)memBase1
+ (unsigned long)inpageoffset
;
331 setup_screen(flags
& VOFLAG_FULLSCREEN
);
333 memset(inpage
, 0, in_width
* in_height
* in_depth
);
335 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_TDFXFB] Screen is %dx%d at %d bpp, in is %dx%d at %d bpp, norm is %dx%d.\n",
336 screenwidth
, screenheight
, screendepth
* 8,
337 in_width
, in_height
, in_depth
* 8,
343 /* Double-buffering draw_alpha */
344 static void draw_alpha_double(int x
, int y
, int w
, int h
, unsigned char *src
,
345 unsigned char *srca
, int stride
)
347 char *dst
= (char *)vidpage
+ ((y
+ vidy
) * screenwidth
+ x
+ vidx
) * screendepth
;
348 alpha_func_double(w
, h
, src
, srca
, stride
, dst
, screenwidth
* screendepth
);
351 /* Single-buffering draw_alpha */
352 static void draw_alpha(int x
, int y
, int w
, int h
, unsigned char *src
,
353 unsigned char *srca
, int stride
)
355 char *dst
= (char *)inpage
+ (y
* in_width
+ x
) * in_depth
;
356 alpha_func(w
, h
, src
, srca
, stride
, dst
, in_width
* in_depth
);
359 static void draw_osd(void)
361 if(!vo_doublebuffering
)
362 vo_draw_text(in_width
, in_height
, draw_alpha
);
365 /* Render onto the screen */
366 static void flip_page(void)
368 voodoo_2d_reg regs
= *reg_2d
; /* Copy the regs */
371 if(vo_doublebuffering
) {
372 /* Flip to an offscreen buffer for rendering */
373 uint32_t t
= vidpageoffset
;
378 vidpageoffset
= hidpageoffset
;
382 reg_2d
->commandExtra
= 0;
383 reg_2d
->clip0Min
= 0;
384 reg_2d
->clip0Max
= 0xffffffff;
386 reg_2d
->srcBaseAddr
= inpageoffset
;
388 reg_2d
->srcFormat
= in_voodoo_format
;
389 reg_2d
->srcSize
= XYREG(in_width
, in_height
);
391 reg_2d
->dstBaseAddr
= vidpageoffset
;
392 reg_2d
->dstXY
= XYREG(vidx
, vidy
);
393 reg_2d
->dstFormat
= vid_voodoo_format
;
394 reg_2d
->dstSize
= XYREG(vidwidth
, vidheight
);
395 reg_2d
->command
= S2S_STRECH_BLT
| S2S_IMMED
| S2S_ROP
;
397 /* Wait for the command to finish (If we don't do this, we get wierd
398 * sound corruption... */
399 while((reg_IO
->status
& 0x1f) < 1)
402 *((volatile uint32_t *)((uint32_t *)reg_IO
+ COMMAND_3D
)) = COMMAND_3D_NOP
;
405 if(!(reg_IO
->status
& STATUS_BUSY
))
408 /* Restore the old regs now */
409 reg_2d
->commandExtra
= regs
.commandExtra
;
410 reg_2d
->clip0Min
= regs
.clip0Min
;
411 reg_2d
->clip0Max
= regs
.clip0Max
;
413 reg_2d
->srcBaseAddr
= regs
.srcBaseAddr
;
414 reg_2d
->srcXY
= regs
.srcXY
;
415 reg_2d
->srcFormat
= regs
.srcFormat
;
416 reg_2d
->srcSize
= regs
.srcSize
;
418 reg_2d
->dstBaseAddr
= regs
.dstBaseAddr
;
419 reg_2d
->dstXY
= regs
.dstXY
;
420 reg_2d
->dstFormat
= regs
.dstFormat
;
421 reg_2d
->dstSize
= regs
.dstSize
;
425 /* Render any text onto this buffer */
426 if(vo_doublebuffering
)
427 vo_draw_text(vidwidth
, vidheight
, draw_alpha_double
);
429 /* And flip to the new buffer! */
430 reg_IO
->vidDesktopStartAddr
= vidpageoffset
;
433 static int draw_frame(uint8_t *src
[])
435 mem2agpcpy(inpage
, src
[0], in_width
* in_depth
* in_height
);
439 static int draw_slice(uint8_t *i
[], int s
[], int w
, int h
, int x
, int y
)
441 /* We want to render to the YUV to the input page + the location
442 * of the stripes we're doing */
443 reg_YUV
->yuvBaseAddr
= inpageoffset
+ in_width
* in_depth
* y
+ x
;
444 reg_YUV
->yuvStride
= in_width
* in_depth
;
446 /* Put the YUV channels into the voodoos internal combiner unit
448 mem2agpcpy_pic(YUV
->Y
, i
[0], s
[0], h
, YUV_STRIDE
, s
[0]);
449 mem2agpcpy_pic(YUV
->U
, i
[1], s
[1], h
/ 2, YUV_STRIDE
, s
[1]);
450 mem2agpcpy_pic(YUV
->V
, i
[2], s
[2], h
/ 2, YUV_STRIDE
, s
[2]);
454 /* Attempt to start doing DR */
455 static uint32_t get_image(mp_image_t
*mpi
)
458 if(mpi
->flags
& MP_IMGFLAG_READABLE
)
460 if(mpi
->type
== MP_IMGTYPE_STATIC
&& vo_doublebuffering
)
462 if(mpi
->type
> MP_IMGTYPE_TEMP
)
463 return VO_FALSE
; // TODO ??
471 mpi
->planes
[0] = (char *)inpage
;
472 mpi
->stride
[0] = in_width
* in_depth
;
478 if(!(mpi
->flags
& MP_IMGFLAG_ACCEPT_STRIDE
) && mpi
->w
!= YUV_STRIDE
)
480 mpi
->planes
[0] = YUV
->Y
;
481 mpi
->planes
[1] = YUV
->U
;
482 mpi
->planes
[2] = YUV
->V
;
483 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = YUV_STRIDE
;
484 reg_YUV
->yuvBaseAddr
= inpageoffset
;
485 reg_YUV
->yuvStride
= in_width
* in_depth
;
492 mpi
->width
= in_width
;
493 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
498 static int control(uint32_t request
, void *data
)
501 case VOCTRL_GET_IMAGE
:
502 return get_image(data
);
504 case VOCTRL_QUERY_FORMAT
:
505 switch(*((uint32_t*)data
)) {
514 return VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
|
515 VFCAP_OSD
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
;
518 return 0; /* Not supported */
520 case VOCTRL_FULLSCREEN
:
521 setup_screen(!vo_fs
);
529 static void check_events(void) {}