vo_3dfx.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 508 行

C
508
字号
/*  *    video_out_3dfx.c * *	Copyright (C) Colin Cross Apr 2000 * *  This file heavily based off of video_out_mga.c of Aaron Holtzman's *  mpeg2dec *	 *  mpeg2dec is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  mpeg2dec is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. *    *  You should have received a copy of the GNU General Public License *  along with mpeg2dec; if not, write to the Free Software *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "video_out.h"#include "video_out_internal.h"#include "x11_common.h"#include <sys/ioctl.h>#include <mplaylib.h>#include <fcntl.h>#include <sys/mman.h>#include <errno.h>#include <wchar.h>#include <signal.h>#include <X11/Xlib.h>#include <X11/extensions/xf86dga.h>#include <X11/Xutil.h>//#define LOG(x) syslog(LOG_USER | LOG_DEBUG,x)#define LOG(x)#include "drivers/3dfx.h"#include "fastmemcpy.h"static vo_info_t info = {	"3dfx (/dev/3dfx)",	"3dfx",	"Colin Cross <colin@MIT.EDU>",	""};LIBVO_EXTERN(3dfx)static uint32_t is_fullscreen = 1;static uint32_t vidwidth;static uint32_t vidheight;static uint32_t screenwidth;static uint32_t screenheight;static uint32_t screendepth = 2; //Only 16bpp supported right nowstatic uint32_t dispwidth = 1280; // You can change these to whatever you wantstatic uint32_t dispheight = 720; // 16:9 screen ratio??static uint32_t dispx;static uint32_t dispy;static uint32_t *vidpage0;static uint32_t *vidpage1;static uint32_t *vidpage2;static uint32_t vidpage0offset;static uint32_t vidpage1offset;static uint32_t vidpage2offset;// Current pointer into framebuffer where display is locatedstatic uint32_t targetoffset;static uint32_t page_space;static voodoo_io_reg *reg_IO;static voodoo_2d_reg *reg_2d;static voodoo_yuv_reg *reg_YUV;static voodoo_yuv_fb *fb_YUV;static uint32_t *memBase0, *memBase1;static uint32_t baseAddr0, baseAddr1;/* X11 related variables */static Display *display;static Window mywindow;static int bpp;static XWindowAttributes attribs;static int fd=-1;static void restore(void) {	//reg_IO->vidDesktopStartAddr = vidpage0offset;	XF86DGADirectVideo(display,0,0);}static void sighup(int foo) {	//reg_IO->vidDesktopStartAddr = vidpage0offset;	XF86DGADirectVideo(display,0,0);	exit(0);}static void restore_regs(voodoo_2d_reg *regs) {	reg_2d->commandExtra = regs->commandExtra;	reg_2d->clip0Min = regs->clip0Min;	reg_2d->clip0Max = regs->clip0Max;	reg_2d->srcBaseAddr = regs->srcBaseAddr;	reg_2d->srcXY = regs->srcXY;	reg_2d->srcFormat = regs->srcFormat;	reg_2d->srcSize = regs->srcSize;	reg_2d->dstBaseAddr = regs->dstBaseAddr;	reg_2d->dstXY = regs->dstXY;	reg_2d->dstFormat = regs->dstFormat;	reg_2d->dstSize = regs->dstSize;	reg_2d->command = 0;}static uint32_t create_window(Display *display, char *title) {	int screen;	unsigned int fg, bg;	XSizeHints hint;	XVisualInfo vinfo;	XEvent xev;	Colormap theCmap;	XSetWindowAttributes xswa;	unsigned long xswamask;	screen = DefaultScreen(display);	hint.x = 0;	hint.y = 10;	hint.width = dispwidth;	hint.height = dispheight;	hint.flags = PPosition | PSize;	bg = WhitePixel(display, screen);	fg = BlackPixel(display, screen);	XGetWindowAttributes(display, DefaultRootWindow(display), &attribs);	bpp = attribs.depth;	if (bpp != 16) 	{		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_Only16BppSupported);		exit(-1);	}	XMatchVisualInfo(display,screen,bpp,TrueColor,&vinfo);	mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_3DFX_VisualIdIs,vinfo.visualid);	theCmap = XCreateColormap(display, RootWindow(display,screen),			vinfo.visual, AllocNone);	xswa.background_pixel = 0;	xswa.border_pixel     = 1;	xswa.colormap         = theCmap;	xswamask = CWBackPixel | CWBorderPixel |CWColormap;	mywindow = XCreateWindow(display, RootWindow(display,screen),				 hint.x, hint.y, hint.width, hint.height, 4, bpp,CopyFromParent,vinfo.visual,xswamask,&xswa);	vo_x11_classhint( display,mywindow,"3dfx" );	XSelectInput(display, mywindow, StructureNotifyMask);	/* Tell other applications about this window */	XSetStandardProperties(display, mywindow, title, title, None, NULL, 0, &hint);	/* Map window. */	XMapWindow(display, mywindow);	/* Wait for map. */	do 	{		XNextEvent(display, &xev);	}	while (xev.type != MapNotify || xev.xmap.event != mywindow);	XSelectInput(display, mywindow, NoEventMask);	XSync(display, False);	return 0;}static void dump_yuv_planar(uint32_t *y, uint32_t *u, uint32_t *v, uint32_t to, uint32_t width, uint32_t height) {	// YUV conversion works like this:	//	//		 We write the Y, U, and V planes separately into 3dfx YUV Planar memory	//		 region.  The nice chip then takes these and packs them into the YUYV	//		 format in the regular frame buffer, starting at yuvBaseAddr, page 2 here.	//		 Then we tell the 3dfx to do a Screen to Screen Stretch BLT to copy all 	//		 of the data on page 2 onto page 1, converting it to 16 bpp RGB as it goes.	//		 The result is a nice image on page 1 ready for display. 	uint32_t j;	uint32_t y_imax, uv_imax, jmax;	reg_YUV->yuvBaseAddr = to;	reg_YUV->yuvStride = screenwidth*2;	LOG("video_out_3dfx: starting planar dump\n");	jmax = height>>1; // vidheight/2, height of U and V planes	y_imax = width; // Y plane is twice as wide as U and V planes	uv_imax = width>>1;  // vidwidth/2/4, width of U and V planes in 32-bit words	for (j=0;j<jmax;j++) 	{		//XXX this should be hand-rolled 32 bit memcpy for safeness.		fast_memcpy(fb_YUV->U + (uint32_t) VOODOO_YUV_STRIDE*  j       ,((uint8_t*) u) + uv_imax*  j       , uv_imax);		fast_memcpy(fb_YUV->V + (uint32_t) VOODOO_YUV_STRIDE*  j       ,((uint8_t*) v) + uv_imax*  j       , uv_imax);		fast_memcpy(fb_YUV->Y + (uint32_t) VOODOO_YUV_STRIDE* (j<<1)   ,((uint8_t*) y) + y_imax * (j<<1)   , y_imax);		fast_memcpy(fb_YUV->Y + (uint32_t) VOODOO_YUV_STRIDE*((j<<1)+1),((uint8_t*) y) + y_imax *((j<<1)+1), y_imax);	}  LOG("video_out_3dfx: done planar dump\n");}static void screen_to_screen_stretch_blt(uint32_t to, uint32_t from, uint32_t width, uint32_t height) {	//FIXME - this function should be called by a show_frame function that	//        uses a series of blts to show only those areas not covered	//        by another window	voodoo_2d_reg saved_regs;	LOG("video_out_3dfx: saving registers\n");	// Save VGA regs (so X kinda works when we're done)	saved_regs = *reg_2d;	/* The following lines set up the screen to screen stretch blt from page2 to		 page 1	*/	LOG("video_out_3dfx: setting blt registers\n");	reg_2d->commandExtra = 4; //disable colorkeying, enable wait for v-refresh (0100b)	reg_2d->clip0Min = 0;	reg_2d->clip0Max = 0xFFFFFFFF; //no clipping	reg_2d->srcBaseAddr = from;	reg_2d->srcXY = 0;	reg_2d->srcFormat = screenwidth*2 | VOODOO_BLT_FORMAT_YUYV; // | 1<<21;	reg_2d->srcSize = vidwidth | (vidheight << 16);	reg_2d->dstBaseAddr = to;	reg_2d->dstXY = 0;	reg_2d->dstFormat = screenwidth*2 | VOODOO_BLT_FORMAT_16;	reg_2d->dstSize = width | (height << 16);	LOG("video_out_3dfx: starting blt\n");	// Executes screen to screen stretch blt	reg_2d->command = 2 | 1<<8 | 0xCC<<24;	LOG("video_out_3dfx: restoring regs\n");	restore_regs(&saved_regs);	LOG("video_out_3dfx: done blt\n");}static void update_target(void) {	uint32_t xp, yp, w, h, b, d;	Window root;	XGetGeometry(display,mywindow,&root,&xp,&yp,&w,&h,&b,&d);	XTranslateCoordinates(display,mywindow,root,0,0,&xp,&yp,&root);	dispx = (uint32_t) xp;	dispy = (uint32_t) yp;	dispwidth = (uint32_t) w;	dispheight = (uint32_t) h;	if (is_fullscreen) 		targetoffset = vidpage0offset + (screenheight - dispheight)/2*screenwidth*screendepth + (screenwidth-dispwidth)/2*screendepth;	else 		targetoffset = vidpage0offset + (dispy*screenwidth + dispx)*screendepth;}static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format) {	char *name = ":0.0";	pioData data;	uint32_t retval;//TODO use x11_common for X and window handling	if(getenv("DISPLAY"))		name = getenv("DISPLAY");	display = XOpenDisplay(name);	screenwidth = XDisplayWidth(display,0);	screenheight = XDisplayHeight(display,0);	page_space = screenwidth*screenheight*screendepth;	vidpage0offset = 0;	vidpage1offset = page_space;  // Use third and fourth pages	vidpage2offset = page_space*2;	signal(SIGALRM,sighup);	//alarm(120);	// Open driver device	if ( fd == -1 ) 	{		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_UnableToOpenDevice);		return -1;	}	// Store sizes for later	vidwidth = width;	vidheight = height;	is_fullscreen = fullscreen = 0;	if (!is_fullscreen) 		create_window(display, title);	// Ask 3dfx driver for base memory address 0	data.port = 0x10; // PCI_BASE_ADDRESS_0_LINUX;	data.size = 4;	data.value = &baseAddr0;	data.device = 0;	if ((retval = ioctl(fd,_IOC(_IOC_READ,'3',3,0),&data)) < 0) 	{		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_Error,retval);		return -1;	}	// Ask 3dfx driver for base memory address 1	data.port = 0x14; // PCI_BASE_ADDRESS_1_LINUX;	data.size = 4;	data.value = &baseAddr1;	data.device = 0;	if ((retval = ioctl(fd,_IOC(_IOC_READ,'3',3,0),&data)) < 0) 	{		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_Error,retval);		return -1;	}	// Map all 3dfx memory areas	memBase0 = mmap(0,0x1000000,PROT_READ | PROT_WRITE,MAP_SHARED,fd,baseAddr0);	memBase1 = mmap(0,3*page_space,PROT_READ | PROT_WRITE,MAP_SHARED,fd,baseAddr1);	if (memBase0 == (uint32_t *) 0xFFFFFFFF || memBase1 == (uint32_t *) 0xFFFFFFFF) 	{		mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_CouldntMapMemoryArea, 		 memBase0,memBase1,errno);	}  	// Set up global pointers	reg_IO  = (void *)memBase0 + VOODOO_IO_REG_OFFSET;	reg_2d  = (void *)memBase0 + VOODOO_2D_REG_OFFSET;	reg_YUV = (void *)memBase0 + VOODOO_YUV_REG_OFFSET;	fb_YUV  = (void *)memBase0 + VOODOO_YUV_PLANE_OFFSET;	vidpage0 = (void *)memBase1 + (unsigned long int)vidpage0offset;	vidpage1 = (void *)memBase1 + (unsigned long int)vidpage1offset;	vidpage2 = (void *)memBase1 + (unsigned long int)vidpage2offset;	// Clear pages 1,2,3 	// leave page 0, that belongs to X.	// So does part of 1.  Oops.	memset(vidpage1,0x00,page_space);	memset(vidpage2,0x00,page_space);	if (is_fullscreen) 		memset(vidpage0,0x00,page_space);#ifndef VOODOO_DEBUG	// Show page 0 (unblanked)	reg_IO->vidDesktopStartAddr = vidpage0offset;	/* Stop X from messing with my video registers!		 Find a better way to do this?		 Currently I use DGA to tell XF86 to not screw with registers, but I can't really use it		 to do FB stuff because I need to know the absolute FB position and offset FB position		 to feed to BLT command 	*/	//XF86DGADirectVideo(display,0,XF86DGADirectGraphics); //| XF86DGADirectMouse | XF86DGADirectKeyb);#endif	atexit(restore);	mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_3DFX_DisplayInitialized,memBase1);	return 0;}static int draw_frame(uint8_t *src[]) {	LOG("video_out_3dfx: starting display_frame\n");	// Put packed data onto page 2	dump_yuv_planar((uint32_t *)src[0],(uint32_t *)src[1],(uint32_t *)src[2],			vidpage2offset,vidwidth,vidheight);	LOG("video_out_3dfx: done display_frame\n");	return 0;}static int //draw_slice(uint8_t *src[], uint32_t slice_num) draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y){	uint32_t target;	target = vidpage2offset + (screenwidth*2 * y);	dump_yuv_planar((uint32_t *)src[0],(uint32_t *)src[1],(uint32_t *)src[2],target,vidwidth,h);	return 0;}static void draw_osd(void){}static void flip_page(void) {	//FIXME - update_target() should be called by event handler when window	//        is resized or moved	update_target();	LOG("video_out_3dfx: calling blt function\n");	screen_to_screen_stretch_blt(targetoffset, vidpage2offset, dispwidth, dispheight);}static intquery_format(uint32_t format){    /* does this supports scaling? up & down? */    switch(format){    case IMGFMT_YV12://    case IMGFMT_YUY2://    case IMGFMT_RGB|24://    case IMGFMT_BGR|24:        return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;    }    return 0;}static voiduninit(void){    if( fd != -1 )        close(fd);}static void check_events(void){}static int preinit(const char *arg){    if ( (fd = open("/dev/3dfx",O_RDWR) ) == -1)     {        mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_UnableToOpenDevice);        return -1;    }                                                            if(arg)     {	mp_msg(MSGT_VO,MSGL_WARN, MSGTR_LIBVO_3DFX_UnknownSubdevice,arg);	return ENOSYS;    }    return 0;}static int control(uint32_t request, void *data, ...){  switch (request) {  case VOCTRL_QUERY_FORMAT:    return query_format(*((uint32_t*)data));  }  return VO_NOTIMPL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?