diff options
-rw-r--r-- | src/mga_video.c | 780 |
1 files changed, 778 insertions, 2 deletions
diff --git a/src/mga_video.c b/src/mga_video.c index 30ae6fc..a2d7979 100644 --- a/src/mga_video.c +++ b/src/mga_video.c @@ -63,6 +63,10 @@ static void MGAResetVideoOverlay(ScrnInfoPtr); static void MGAVideoTimerCallback(ScrnInfoPtr pScrn, Time time); +static XF86VideoAdaptorPtr MGASetupImageVideoILOAD(ScreenPtr); +static int MGAPutImageILOAD(ScrnInfoPtr, short, short, short, short, short, + short, short, short, int, unsigned char*, short, + short, Bool, RegionPtr, pointer, DrawablePtr); #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) @@ -91,12 +95,27 @@ void MGAInitVideo(ScreenPtr pScreen) if((pScrn->bitsPerPixel != 8) && !pMga->NoAccel && (pMga->SecondCrtc == FALSE) && - ((pMga->Chipset == PCI_CHIP_MGAG200) || + ((pMga->Chipset == PCI_CHIP_MGA2164) || + (pMga->Chipset == PCI_CHIP_MGA2164_AGP) || +/* (pMga->Chipset == PCI_CHIP_MGA2064) || */ + (pMga->Chipset == PCI_CHIP_MGAG200) || (pMga->Chipset == PCI_CHIP_MGAG200_PCI) || (pMga->Chipset == PCI_CHIP_MGAG400) || (pMga->Chipset == PCI_CHIP_MGAG550))) { - if((pMga->Overlay8Plus24 || pMga->TexturedVideo) && + if( (pMga->Chipset == PCI_CHIP_MGA2164) || +/* (pMga->Chipset == PCI_CHIP_MGA2064) || */ + (pMga->Chipset == PCI_CHIP_MGA2164_AGP) + ) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using MGA 2164W ILOAD video\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "This is an experimental driver and may not work on your machine.\n"); + + newAdaptor = MGASetupImageVideoILOAD(pScreen); + pMga->TexturedVideo = TRUE; + /* ^^^ this is not really true but the ILOAD scaler shares + much more code with the textured video than the overlay */ + } else if((pMga->Overlay8Plus24 || pMga->TexturedVideo) && (pScrn->bitsPerPixel != 24)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using texture video\n"); @@ -1258,3 +1277,760 @@ MGAInitOffscreenImages(ScreenPtr pScreen) xf86XVRegisterOffscreenImages(pScreen, offscreenImages, num); } + + +/* Matrox MGA 2164W Xv extension support. +* The extension is implemented as a HOST->FB image load in YUV format. +* I decided not to use real hardware overlay since on the Millennium II +* it would limit the size of the frame buffer to 4Mb (even on a 16Mb +* card) due to an hardware limitation. +* Author: Gabriele Gorla (gorlik@yahoo.com) +* Based on the MGA-Gxxx Xv extension by: Mark Vojkovich + */ + +/* This code is still in alpha stage. Only YUV->RGB conversion + and horizontal scaling are hardware accelerated. + All 4 FOURCC formats supported by X should be supported. + It has been tested only on my DEC XP1000 at 1024x768x32 under + linux 2.6.18 with X.org 7.1.1 (debian alpha) + + Bug reports and success/failure stories are greatly appreciated. +*/ + +/* #define DEBUG_MGA2164 */ +/* #define CUSTOM_MEMCOPY */ +#define MGA2164_SWFILTER + + +static XF86VideoAdaptorPtr +MGASetupImageVideoILOAD(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + XF86VideoAdaptorPtr adapt; + MGAPtr pMga = MGAPTR(pScrn); + + adapt = MGAAllocAdaptor(pScrn, FALSE); + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "Matrox Millennium II ILOAD Video Engine"; + adapt->nEncodings = 1; + adapt->pEncodings = &DummyEncoding[1]; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = MGA_MAX_PORTS; + adapt->pAttributes = NULL; + adapt->nAttributes = 0; + + /* number of supported color formats */ + adapt->pImages = Images; + adapt->nImages = 4; + + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = MGAStopVideo; + + adapt->SetPortAttribute = MGASetPortAttributeTexture; + adapt->GetPortAttribute = MGAGetPortAttributeTexture; + adapt->QueryBestSize = MGAQueryBestSize; + adapt->PutImage = MGAPutImageILOAD; + adapt->QueryImageAttributes = MGAQueryImageAttributes; + + REGION_INIT(pScreen, &(pMga->portPrivate->clip), NullBox, 0); + + return adapt; +} + +/* this function is optimized for alpha. It might be better also for +other load/store risc architectures but I never tested on anything else +than my ev56 */ +static void CopyMungedScanline_AXP(CARD32 *fb_ptr, short src_w, + CARD32 *tsp, CARD32 *tpu, CARD32 *tpv) +{ + CARD32 k,y0,y1,u,v; + + for(k=src_w/8;k;k--) { + y0=*tsp; + y1=*(tsp+1); + u=*tpu; + v=*tpv; + + *(fb_ptr)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) | + (v&0x00ff0000)<<8 | (u&0x00ff0000)>>8; + *(fb_ptr+1)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) | + (v&0x00ff0000)<<8 | (u&0x00ff0000)>>8; + + *(fb_ptr+2)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) | + (v&0x000000ff)<<24 | (u&0x000000ff)<<8; + *(fb_ptr+3)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) | + (v&0x000000ff)<<24 | (u&0x000000ff)<<8; + + /*correct below*/ + /* *(fb_ptr)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) | + (v&0x000000ff)<<24 | (u&0x000000ff)<<8; + *(fb_ptr+1)=((y0&0x00ff0000)>>16)|((y0&0xff000000)>>8) | + (v&0x0000ff00)<<16 | (u&0x0000ff00); + *(fb_ptr+2)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) | + (v&0x00ff0000)<<8 | (u&0x00ff0000)>>8; + *(fb_ptr+3)=((y1&0x00ff0000)>>16)|((y1&0xff000000)>>8) | + (v&0xff000000) | (u&0xff000000)>>16; */ + + tsp+=2; tpu++; tpv++; + fb_ptr+=4; + } +} + +static void CopyMungedScanline_AXP2(CARD32 *fb_ptr, short src_w, + CARD32 *tsp, CARD32 *tpu, CARD32 *tpv) +{ + CARD8 *y, *u, *v; + int k; + y=(CARD8 *)tsp; + u=(CARD8 *)tpu; + v=(CARD8 *)tpv; + + for(k=src_w/8;k;k--) { + fb_ptr[0]=y[0] | y[1]<<16 | v[0]<<24 | u[0]<<8; + fb_ptr[1]=y[2] | y[3]<<16 | v[1]<<24 | u[1]<<8; + fb_ptr[2]=y[4] | y[5]<<16 | v[2]<<24 | u[2]<<8; + fb_ptr[3]=y[6] | y[7]<<16 | v[3]<<24 | u[3]<<8; + + y+=8; u+=4; v+=4; + fb_ptr+=4; + } +} + + +static void CopyMungedScanlineFilter_AXP(CARD32 *fb_ptr, short src_w, + CARD32 *tsp1, CARD32 *tpu1, CARD32 *tpv1, + CARD32 *tsp2, CARD32 *tpu2, CARD32 *tpv2, + int beta, int xds ) +{ + unsigned int k,y0_1,y1_1,y0_2,y1_2,u,v; + int yf[8], uf[4], vf[4]; + int oneminbeta = 0xff - beta; + + for(k=xds*src_w/8;k;k--) { + y0_1=*tsp1; + y1_1=*(tsp1+1); + y0_2=*tsp2; + y1_2=*(tsp2+1); + u=*tpu1; + v=*tpv1; + + tsp1+=2; tsp2+=2; tpu1++; tpv1++; + yf[0] = ((y0_1&0x000000ff)*oneminbeta + (y0_2&0x000000ff)*beta )>>8; + yf[1] = (((y0_1&0x0000ff00)>>8)*oneminbeta + ((y0_2&0x0000ff00)>>8)*beta )>>8; + yf[2] = (((y0_1&0x00ff0000)>>16)*oneminbeta + ((y0_2&0x00ff0000)>>16)*beta )>>8; + yf[3] = (((y0_1&0xff000000)>>24)*oneminbeta + ((y0_2&0xff000000)>>24)*beta )>>8; + yf[4] = ((y1_1&0x000000ff)*oneminbeta + (y1_2&0x000000ff)*beta )>>8; + yf[5] = (((y1_1&0x0000ff00)>>8)*oneminbeta + ((y1_2&0x0000ff00)>>8)*beta )>>8; + yf[6] = (((y1_1&0x00ff0000)>>16)*oneminbeta + ((y1_2&0x00ff0000)>>16)*beta )>>8; + yf[7] = (((y1_1&0xff000000)>>24)*oneminbeta + ((y1_2&0xff000000)>>24)*beta )>>8; + + /* FIXME: there is still no filtering on u and v */ + uf[0]=(u&0x000000ff); + uf[1]=(u&0x0000ff00)>>8; + uf[2]=(u&0x00ff0000)>>16; + uf[3]=(u&0xff000000)>>24; + + vf[0]=(v&0x000000ff); + vf[1]=(v&0x0000ff00)>>8; + vf[2]=(v&0x00ff0000)>>16; + vf[3]=(v&0xff000000)>>24; + + switch(xds) { + case 1: + *(fb_ptr)=(yf[0]) | (yf[1]<<16) | + vf[0]<<24 | uf[0]<<8; + *(fb_ptr+1)=(yf[2]) | (yf[3]<<16) | + vf[1]<<24 | uf[1]<<8; + *(fb_ptr+2)=(yf[4]) | (yf[5]<<16) | + vf[2]<<24 | uf[2]<<8; + *(fb_ptr+3)=(yf[6]) | (yf[7]<<16) | + vf[3]<<24 | uf[3]<<8; + fb_ptr+=4; + break; + + case 2: + *(fb_ptr)=(yf[0]+yf[1])/2 | (((yf[2]+yf[3])/2)<<16) | + ((vf[0]+vf[1])/2 )<<24 | ((uf[0]+uf[1])/2)<<8; + *(fb_ptr+1)=(yf[4]+yf[5])/2 | ( ((yf[6]+yf[7])/2) <<16) | + ((vf[2]+vf[3])/2 )<<24 | ((uf[2]+uf[3])/2)<<8; + fb_ptr+=2; + break; + + case 4: + *(fb_ptr)=(yf[0]+yf[1]+yf[2]+yf[3])/4 | (((yf[4]+yf[5]+yf[6]+yf[7])/4)<<16) | + ((vf[0]+vf[1]+vf[2]+vf[3])/4 )<<24 | ((uf[0]+uf[1]+uf[2]+uf[3])/4)<<8; + fb_ptr+=1; + break; + + default: + break; + } + } +} + +static void CopyMungedScanlineFilterDown_AXP(CARD32 *fb_ptr, short src_w, + CARD32 *tsp1, CARD32 *tpu1, CARD32 *tpv1, + CARD32 *tsp2, CARD32 *tpu2, CARD32 *tpv2, + int beta , int xds) +{ + unsigned int k,y0_1,y1_1,y0_2,y1_2,u,v; + int yf[8], uf[4], vf[4]; + + for(k=src_w/8;k;k--) { + y0_1=*tsp1; + y1_1=*(tsp1+1); + y0_2=*tsp2; + y1_2=*(tsp2+1); + u=*tpu1; + v=*tpv1; + + tsp1+=2; tsp2+=2; tpu1++; tpv1++; + yf[0] = ((y0_1&0x000000ff) + (y0_2&0x000000ff))>>8; + yf[1] = (((y0_1&0x0000ff00)>>8) + ((y0_2&0x0000ff00)>>8))>>8; + yf[2] = (((y0_1&0x00ff0000)>>16) + ((y0_2&0x00ff0000)>>16))>>8; + yf[3] = (((y0_1&0x000000ff)>>24) + ((y0_2&0x000000ff)>>24))>>8; + yf[4] = ((y1_1&0x000000ff) + (y1_2&0x000000ff))>>8; + yf[5] = (((y1_1&0x0000ff00)>>8) + ((y1_2&0x0000ff00)>>8))>>8; + yf[6] = (((y1_1&0x00ff0000)>>16) + ((y1_2&0x00ff0000)>>16))>>8; + yf[7] = (((y1_1&0x000000ff)>>24) + ((y1_2&0x000000ff)>>24))>>8; + + *(fb_ptr)=(yf[0]) | (yf[1]<<16) | + (v&0x000000ff)<<24 | (u&0x000000ff)<<8; + *(fb_ptr+1)=(yf[2]) | (yf[3]<<16) | + (v&0x0000ff00)<<16 | (u&0x0000ff00); + *(fb_ptr+2)=(yf[4]) | (yf[5]<<16) | + (v&0x00ff0000)<<8 | (u&0x00ff0000)>>8; + *(fb_ptr+3)=(yf[6]) | (yf[7]<<16) | + (v&0xff000000) | (u&0xff000000)>>16; + + fb_ptr+=4; + } +} + +static void MGACopyScaledILOAD( + ScrnInfoPtr pScrn, + int id, unsigned char *buf, + BoxPtr pbox, + int width, int height, int pitch, + short src_x, short src_y, + short src_w, short src_h, + short drw_x, short drw_y, + short drw_w, short drw_h + ) +{ + MGAPtr pMga = MGAPTR(pScrn); + CARD32 *fb_ptr; + unsigned char *ubuf, *vbuf, *tbuf; + CARD32 *pu, *pv; + int k,l, pl, dl, xds, yds; + short box_h; + short scr_pitch = ( pScrn->virtualX + 15) & ~15; + +#ifdef DEBUG_MGA2164 + char sbuf[255]; + + sprintf(sbuf,"---- PBOX: x1=%d y1=%d w=%d h=%d (x2=%d y2=%d)\n", + pbox->x1,pbox->y1,pbox->x2-pbox->x1,pbox->y2-pbox->y1, + pbox->x2,pbox->y2); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + + sprintf(sbuf,"in src: src_x=%d src_y=%d src_w=%d src_h=%d\n", + src_x,src_y,src_w,src_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + sprintf(sbuf,"in drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n", + drw_x,drw_y,drw_w,drw_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + /* scaling yuv->rgb */ + + /* hack to force width and src image to be 8 pixel aligned */ + src_x&=~0x7; + src_w&=~0x7; + + box_h=pbox->y2-pbox->y1; + + /* compute X down scaling factor */ + if(src_w>drw_w) { + if(src_w/2<drw_w) { + xds=2; + } else if(src_w/4<drw_w) { + xds=4; + } else { xds=8; } + } else xds = 1; + + /* prevent crashing when dragging window outside left boundary of screen */ + /* FIXME: need to implement per pixel left start to avoid undesired + effects when dragging window outside left screen boundary */ + + if(drw_x<0) { + src_x=( -(drw_x*src_w)/drw_w + 0x7)&~0x7; + src_w-=src_x; + drw_w+=drw_x; + drw_x=0; + } + + src_w/=xds; + + /* compute X down scaling factor */ + if(src_h>drw_h) { + if(src_h/2<drw_h) { + yds=2; + } else if(src_h/4<drw_h) { + yds=4; + } else { yds=8; } + } else yds = 1; + + +#ifdef DEBUG_MGA2164 + char sbuf[255]; + + sprintf(sbuf,"---- xds = %d\n", + xds); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + +#ifdef DEBUG_MGA2164 + sprintf(sbuf,"out src: src_x=%d src_y=%d src_w=%d src_h=%d\n", + src_x,src_y,src_w,src_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + sprintf(sbuf,"out drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n", + drw_x,drw_y,drw_w,drw_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + CHECK_DMA_QUIESCENT(pMga, pScrn); + + /* scaling ILOAD */ + + vbuf=buf+width*height; + ubuf=vbuf+width*height/4; + pu = (CARD32 *)(ubuf+(src_y/2)*(width/2)); + pv = (CARD32 *)(vbuf+(src_y/2)*(width/2)); + + for(pl=-1,dl=0;dl<box_h;dl++) { + int beta; + l=(dl+(pbox->y1-drw_y))*src_h/drw_h; + /* FIXME: check the math */ + beta = ((dl+(pbox->y1-drw_y))*src_h*0xff/drw_h) - ((dl+(pbox->y1-drw_y))*src_h/drw_h*0xff); + +#ifdef MGA2164_BLIT_DUP + if(l!=pl) +#else + if(1) +#endif + { + + /* + #ifdef DEBUG_MGA2164 + sprintf(sbuf,"new line: scr_dst %d img_src %d prev %d\n", + dl,l,pl); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + #endif + */ + + OUTREG(MGAREG_DWGCTL, MGADWG_ILOAD_HIQH | MGADWG_BUYUV | MGADWG_SHIFTZERO + | MGADWG_SGNZERO | 0xc0000); + + OUTREG(MGAREG_AR0, pbox->x1 + drw_w -1); /* SRC LINE END why -1 ? */ + OUTREG(MGAREG_AR2, ( ( (src_w-1)<<16) / (drw_w-1)) + 1 ); /* ((SRC_X_DIM -1)<<16) / (DST_X_DIM-1) +1 */ + OUTREG(MGAREG_AR3, pbox->x1 ); /* SRC LINE START*/ + OUTREG(MGAREG_AR5, scr_pitch); /* DST_Y_INCR = PITCH? */ + OUTREG(MGAREG_AR6, ((src_w-drw_w)<<16) / (drw_w-1) ); /* */ + OUTREG(MGAREG_FXBNDRY, drw_x|((drw_x+drw_w-1)<<16) ); /* why -1 ? */ + OUTREG(MGAREG_CXBNDRY, pbox->x1 | ((pbox->x2-1)<<16 ) ); + OUTREG(MGAREG_YDST , pbox->y1+dl ); /* Y_START_POS */ + OUTREG(MGAREG_LEN + MGAREG_EXEC , 1); /* # of LINES */ + + /* xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Data finished\n"); */ + + fb_ptr=(CARD32 *)pMga->ILOADBase; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + tbuf=buf+(l+src_y)*width; + { + CARD32 *tpu=pu+src_x/8+l/2*width/8; + CARD32 *tpv=pv+src_x/8+l/2*width/8; + CARD32 *tsp=(CARD32 *)(tbuf+src_x), *tsp2; + + if((l+src_y)<(src_h-1)) + tsp2=(CARD32 *)(tbuf+src_x+width); + else + tsp2=(CARD32 *)(tbuf+src_x); + + /* it is not clear if waiting is actually good for performance */ + /* WAITFIFO(pMga->FifoSize);*/ + /* should try to get MGACopyMunged data to work here */ + /* CopyMungedScanline_AXP(fb_ptr,src_w,tsp,tpu,tpv); */ + + /* Filter does not work yet */ + CopyMungedScanlineFilter_AXP(fb_ptr,src_w,tsp,tpu,tpv,tsp2,tpu,tpv, beta, xds); + /* if(l&1) { + pu+=width/8; + pv+=width/8; + } */ + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + tbuf=buf+(l+src_y)*width*2; + +#ifndef MGA2164_SWFILTER + WAITFIFO(pMga->FifoSize/2); + memcpy(fb_ptr, tbuf+src_x*2, src_w*2); + fb_ptr+=src_w*2; /* pointer in the pseudo dma window */ +#else + { + CARD32 *tsp=(CARD32 *)(tbuf+src_x*2), *tsp2; + + if((l+src_y)<(src_h-1)) + tsp2=(CARD32 *)(tbuf+src_x*2+width*2); + else + tsp2=(CARD32 *)(tbuf+src_x*2); + /* { + char sbuf [256]; + sprintf(sbuf,"dst line: %d src_line: %d beta: %x\n", + dl, l, beta ); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + } */ + + WAITFIFO(pMga->FifoSize/4); + for(k=xds*src_w/8;k;k--) { + int oneminbeta = 0xff-beta; + int y[8], u[4], v[4], ya[4], ua[2], va[2], p; + + switch(yds) { + case 1: + /* upscale y filter */ + for(p=0;p<4;p++) { + y[2*p]=(((*(tsp+p)&0x000000ff))*oneminbeta+((*(tsp2+p)&0x000000ff))*beta)>>8; + y[2*p+1]=(((*(tsp+p)&0x00ff0000)>>16)*oneminbeta+((*(tsp2+p)&0x00ff0000)>>16)*beta)>>8; + u[p]=(((*(tsp+p)&0x0000ff00)>>8)*oneminbeta+((*(tsp2+p)&0x0000ff00)>>8)*beta)>>8; + v[p]=(((*(tsp+p)&0xff000000)>>24)*oneminbeta+((*(tsp2+p)&0xff000000)>>24)*beta)>>8; + } + break; + /* downscale y filter */ + case 2: + case 3: + case 4: + default: + for(p=0;p<4;p++) { + y[2*p]=(((*(tsp+p)&0x000000ff))); + y[2*p+1]=(((*(tsp+p)&0x00ff0000)>>16)); + u[p]=(((*(tsp+p)&0x0000ff00)>>8)); + v[p]=(((*(tsp+p)&0xff000000)>>24)); + } + break; + } + + switch (xds) { + case 1: /* simple copy */ + *(fb_ptr++)=y[0]|y[1]<<16|u[0]<<8|v[0]<<24; + *(fb_ptr++)=y[2]|y[3]<<16|u[1]<<8|v[1]<<24; + *(fb_ptr++)=y[4]|y[5]<<16|u[2]<<8|v[2]<<24; + *(fb_ptr++)=y[6]|y[7]<<16|u[3]<<8|v[3]<<24; + break; + case 2: /* dowscale by 2 */ + ya[0]=(y[0]+y[1])>>1; + ya[1]=(y[2]+y[3])>>1; + ya[2]=(y[4]+y[5])>>1; + ya[3]=(y[6]+y[7])>>1; + ua[0]=(u[0]+u[1])>>1; + ua[1]=(u[2]+u[3])>>1; + va[0]=(v[0]+v[1])>>1; + va[1]=(v[2]+v[3])>>1; + *(fb_ptr++)=ya[0]|ya[1]<<16|ua[0]<<8|va[0]<<24; + *(fb_ptr++)=ya[2]|ya[3]<<16|ua[1]<<8|va[1]<<24; + break; + case 4: /* downscale by 4 */ + ya[0]=(y[0]+y[1]+y[2]+y[3])>>2; + ya[1]=(y[4]+y[5]+y[6]+y[7])>>2; + ua[0]=(u[0]+u[1]+u[2]+u[3])>>2; + va[0]=(v[0]+v[1]+v[2]+v[3])>>2; + *(fb_ptr++)=ya[0]|ya[1]<<16|ua[0]<<8|va[0]<<24; + break; + case 8: + default: + break; + } + + /* fb_ptr+=4; */ + tsp+=4; tsp2+=4; + } + } +#endif /* MGA2164_SWFILTER */ + break; + default: + break; + } + pl=l; + } else { + /* dup lines */ + +#ifdef DEBUG_MGA2164 + sprintf(sbuf,"dup line: scr_src %d scr_dst %d\n", + dl-1,dl); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + OUTREG(MGAREG_DWGCTL, 0x040C6008); + OUTREG(MGAREG_FXBNDRY, pbox->x1|((pbox->x2-1)<<16) ); /* why -1 ? */ + OUTREG(MGAREG_AR3, (pbox->y1+dl-1)*scr_pitch+pbox->x1 ); /* SRC LINE START*/ + OUTREG(MGAREG_AR0, (pbox->y1+dl-1)*scr_pitch+pbox->x2 -1); /* SRC LINE END why -1 ? */ + OUTREG(MGAREG_AR5, scr_pitch); /* DST_Y_INCR = PITCH? */ + OUTREG(MGAREG_YDST , pbox->y1+dl); /* Y_START_POS */ + OUTREG(MGAREG_LEN + MGAREG_EXEC , 1); /* # of LINES */ + } + } + OUTREG(MGAREG_CXBNDRY, 0xFFFF0000); +} + +static void MGACopyILOAD( + ScrnInfoPtr pScrn, + int id, unsigned char *buf, + BoxPtr pbox, + int width, int height, int pitch, + short src_x, short src_y, + short src_w, short src_h, + short drw_x, short drw_y, + short drw_w, short drw_h + ) +{ + MGAPtr pMga = MGAPTR(pScrn); + CARD32 *fb_ptr; + CARD8 *ubuf, *vbuf; + CARD32 *pu, *pv; + int k,l; + short clip_x1, clip_x2, tmp_w; + +#ifdef DEBUG_MGA2164 + char sbuf[255]; + + sprintf(sbuf,"---- PBOX: x1=%d y1=%d w=%d h=%d (x2=%d y2=%d)\n", + pbox->x1,pbox->y1,pbox->x2-pbox->x1,pbox->y2-pbox->y1, + pbox->x2,pbox->y2); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + + sprintf(sbuf,"in src: src_x=%d src_y=%d src_w=%d src_h=%d\n", + src_x,src_y,src_w,src_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + sprintf(sbuf,"in drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n", + drw_x,drw_y,drw_w,drw_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + /* non-scaling yuv->rgb */ + + /* hack to force width and src image to be 8 pixel aligned */ + src_x&=~0x7; + src_w&=~0x7; + drw_w&=~0x7; + tmp_w=drw_w; + clip_x1=drw_x; + clip_x2=drw_x+drw_w; + + /* hack for clipping in non scaling version */ + /* this works only if no scaling */ + if(pbox->x1 > drw_x) { /* left side X clipping*/ + src_x+=((pbox->x1-drw_x)&~0x7); + src_w-=((pbox->x1-drw_x)&~0x7); + clip_x1=pbox->x1; + drw_x+=src_x; + drw_w=src_w; + } + + if( (pbox->x2) < (drw_x+drw_w) ) { /* right side X clipping */ + tmp_w=( (pbox->x2) - drw_x ); + drw_w= tmp_w & (~0x7); + if(drw_w!=tmp_w) drw_w+=8; + clip_x2=drw_x+tmp_w-1; /* not sure why needs -1 */ + src_w=drw_w; + } + + if(pbox->y1 > drw_y) { /* top side Y clipping */ + src_y+=(pbox->y1-drw_y); + src_h-=(pbox->y1-drw_y); + drw_y+=src_y; + drw_h=src_h; + } + if((pbox->y2)<(drw_y+drw_h)) { /* bottom side Y clipping */ + drw_h=(pbox->y2)-drw_y; + src_h=drw_h; + } + + if(drw_x<0) drw_x=0; + +#ifdef DEBUG_MGA2164 + sprintf(sbuf,"out src: src_x=%d src_y=%d src_w=%d src_h=%d\n", + src_x,src_y,src_w,src_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); + sprintf(sbuf,"out drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n", + drw_x,drw_y,drw_w,drw_h); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); +#endif + + /* ready to draw */ + if(drw_w==0||drw_h==0) return; + + if(drw_w<0||drw_h<0) { + /* actually until scaling is working this might happen + during normal operation */ + /* sprintf(sbuf,"drw_w or drw_h are negative (this should never + happen)\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); */ + return; + } + + CHECK_DMA_QUIESCENT(pMga, pScrn); + + /* non scaling ILOAD */ + WAITFIFO(6); + OUTREG(MGAREG_AR5, 0); + OUTREG(MGAREG_DWGCTL, MGADWG_ILOAD | MGADWG_BUYUV | MGADWG_SHIFTZERO + | MGADWG_SGNZERO | 0xc0000); + OUTREG(MGAREG_AR0, (drw_w)-1 ); + OUTREG(MGAREG_AR3, 0); + OUTREG(MGAREG_CXBNDRY, clip_x1|(clip_x2<<16)); + OUTREG(MGAREG_FXBNDRY, drw_x|((drw_x+drw_w-1)<<16)); + OUTREG(MGAREG_YDSTLEN + MGAREG_EXEC , (drw_y<<16)|drw_h); + + fb_ptr=(CARD32 *)pMga->ILOADBase; + vbuf=buf+width*height; + ubuf=vbuf+width*height/4; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + pu = (CARD32 *)(ubuf+(src_y/2)*(width/2)); + pv = (CARD32 *)(vbuf+(src_y/2)*(width/2)); + buf+=src_y*width; + + for(l=0;l<drw_h;l++) { + CARD32 *tpu=pu+src_x/8; + CARD32 *tpv=pv+src_x/8; + CARD32 *tsp=(CARD32 *)(buf+src_x); + + /* it is not clear if waiting is actually good for performance */ + /* WAITFIFO(pMga->FifoSize);*/ + /* should try to get MGACopyMunged data to work here */ + CopyMungedScanline_AXP(fb_ptr,src_w,tsp,tpu,tpv); + buf+=width; + if(l&1) { + pu+=width/8; + pv+=width/8; + } + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + buf+=src_y*width*2; + for(l=0;l<drw_h;l++) { + +#ifndef CUSTOM_MEMCOPY + WAITFIFO(pMga->FifoSize/2); /* not sure what's the value for best performance */ + memcpy(fb_ptr, buf+src_x*2, src_w*2); + fb_ptr+=src_w*2; +#else + CARD32 *tsp=(CARD32 *)(buf+src_x*2); + WAITFIFO(pMga->FifoSize/4); + for(k=src_w/8;k;k--) { + *(fb_ptr)=*(tsp); + *(fb_ptr+1)=*(tsp+1); + *(fb_ptr+2)=*(tsp+2); + *(fb_ptr+3)=*(tsp+3); + fb_ptr+=4; tsp+=4; + } +#endif /* CUSTOM_MEMCOPY */ + buf+=width*2; + } + break; + default: + break; + } + OUTREG(MGAREG_CXBNDRY, 0xFFFF0000); /* put clipping back to normal */ +} + +static int +MGAPutImageILOAD( + ScrnInfoPtr pScrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char* buf, + short width, short height, + Bool Sync, + RegionPtr clipBoxes, pointer data, + DrawablePtr pDraw + ){ + MGAPtr pMga = MGAPTR(pScrn); + MGAPortPrivPtr pPriv = pMga->portPrivate; + INT32 x1, x2, y1, y2; + int dstPitch = 0; + int bpp; + BoxRec dstBox; + int nbox; + BoxPtr pbox; + + /* Clip */ + x1 = src_x; x2 = src_x + src_w; + y1 = src_y; y2 = src_y + src_h; + + dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; + + if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, + clipBoxes, width, height)) + return Success; + + bpp = pScrn->bitsPerPixel >> 3; + + if( pMga->AccelInfoRec->NeedToSync && ((long)data != pPriv->lastPort) ) { + MGAStormSync(pScrn); + } + + pPriv->lastPort = (long)data; + nbox=REGION_NUM_RECTS(clipBoxes); + pbox=REGION_RECTS(clipBoxes); + + while(nbox--) { + + if ( (drw_w==src_w) && (drw_h==src_h) && (drw_x >= 0 ) ) { + /* special case 1: non scaling optimization */ + MGACopyILOAD(pScrn,id,buf,pbox, + width, height, dstPitch, src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h); +#if 0 + } else if ( (drw_w>src_w) && (drw_h>src_h) && (drw_x >= 0 ) ) { + /* special case 2: upscaling for full screen apps */ + /* FIXME: to do */ + MGACopyScaledILOAD(pScrn,id,buf,pbox, + width, height, dstPitch, src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h); + +#endif + } else /* generic fallback case */ + MGACopyScaledILOAD(pScrn,id,buf,pbox, + width, height, dstPitch, src_x, src_y, src_w, src_h, + drw_x, drw_y, drw_w, drw_h); + /* FIXME: when the generic is perfect I will enable the optimizations */ + pbox++; + } + + + pMga->AccelInfoRec->NeedToSync = TRUE; + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + pMga->VideoTimerCallback = MGAVideoTimerCallback; + + return Success; +} |