diff options
Diffstat (limited to 'xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c')
-rw-r--r-- | xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c | 1587 |
1 files changed, 974 insertions, 613 deletions
diff --git a/xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c b/xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c index 8480de20a..d63592085 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c @@ -1,85 +1,134 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c,v 1.5 2000/12/08 21:53:37 mvojkovi Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_video.c,v 1.2 2000/12/02 15:30:57 tsi Exp $ */ -/* Adapted from ../mga/mga_video.c */ +#ifndef XvExtension +void TDFXInitVideo(ScreenPtr pScreen) {} +void TDFXCloseVideo(ScreenPtr pScreen) {} +#else #include "xf86.h" -#include "xf86_OSproc.h" -#include "xf86Resources.h" -#include "xf86_ansic.h" -#include "compiler.h" -#include "xf86PciInfo.h" -#include "xf86Pci.h" -#include "xf86fbman.h" -#include "regionstr.h" - #include "tdfx.h" +#include "dixstruct.h" -#include "xf86xv.h" #include "Xv.h" -#include "xaa.h" -#include "xaalocal.h" -#include "dixstruct.h" #include "fourcc.h" +static Atom xvColorKey, xvFilterQuality; + /* These should move into tdfxdefs.h with better names */ -#define YUV_Y_BASE 0xC00000 -#define YUV_U_BASE 0xD00000 -#define YUV_V_BASE 0xE00000 +#define YUV_Y_BASE 0xC00000 +#define YUV_U_BASE 0xD00000 +#define YUV_V_BASE 0xE00000 -#define SST_2D_FORMAT_YUYV 0x8 -#define SST_2D_FORMAT_UYVY 0x9 +#define SST_2D_FORMAT_YUYV 0x8 +#define SST_2D_FORMAT_UYVY 0x9 #define YUVBASEADDR 0x80100 -/* This should move to tdfx.h - * Only one port for now due to need for better memory allocation. */ -#define TDFX_MAX_PORTS 1 - #define YUVSTRIDE 0x80104 +#define VIDPROCCFGMASK 0xa2e3eb6c -#ifndef XvExtension -void TDFXInitVideo(ScreenPtr pScreen) {} -#else +#define OFF_DELAY 250 /* milliseconds */ +#define FREE_DELAY 15000 + +#define OFF_TIMER 0x01 +#define FREE_TIMER 0x02 +#define CLIENT_VIDEO_ON 0x04 +#define TIMER_MASK (OFF_TIMER | FREE_TIMER) + +#define TDFX_MAX_OVERLAY_PORTS 1 +#define TDFX_MAX_TEXTURE_PORTS 32 + +/* Doesn't matter what screen we use */ +#define DummyScreen screenInfo.screens[0] +/* Needed for attribute atoms */ +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* + * PROTOTYPES + */ void TDFXInitVideo(ScreenPtr pScreen); -void TDFXCloseVideo (ScreenPtr pScreen); - -static XF86VideoAdaptorPtr TDFXSetupImageVideo(ScreenPtr); -static int TDFXSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); -static int TDFXGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); - -static void TDFXStopVideo(ScrnInfoPtr, pointer, Bool); -static void TDFXQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, - unsigned int *, unsigned int *, pointer); -static int TDFXPutImage(ScrnInfoPtr, short, short, short, short, short, - short, short, short, int, unsigned char*, short, - short, Bool, RegionPtr, pointer); -#if 0 -/* This isn't done yet, but eventually it will put images to the - * video overlay. */ -static int TDFXPutImageOverlay(ScrnInfoPtr pScrn, short, short, - short, short, short, short, - short, short, int, unsigned char*, - short, short, Bool, RegionPtr , pointer); -#endif - -static int TDFXQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, - unsigned short *, int *, int *); - -/* These function is from tdfx_accel.c */ -extern void TDFXFirstSync(ScrnInfoPtr pScrn); +void TDFXCloseVideo(ScreenPtr pScreen); -static FBAreaPtr -TDFXAllocateOffscreenBuffer (ScrnInfoPtr pScrn, int id, int width, int height); +static FBAreaPtr TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height); +static FBLinearPtr TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size); +static void TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time); -static void -TDFXDeallocateOffscreenBuffer (ScrnInfoPtr pScrn, int id); +static XF86VideoAdaptorPtr TDFXSetupImageVideoTexture(ScreenPtr); +static int TDFXSetPortAttributeTexture(ScrnInfoPtr, Atom, INT32, pointer); +static int TDFXGetPortAttributeTexture(ScrnInfoPtr, Atom ,INT32 *, pointer); +static int TDFXPutImageTexture(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer); +static void TDFXStopVideoTexture(ScrnInfoPtr, pointer, Bool); + +static XF86VideoAdaptorPtr TDFXSetupImageVideoOverlay(ScreenPtr); +static int TDFXSetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); +static int TDFXGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer); +static int TDFXPutImageOverlay(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer); +static void TDFXStopVideoOverlay(ScrnInfoPtr, pointer, Bool); +static void TDFXResetVideoOverlay(ScrnInfoPtr); + +static void TDFXQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer); +static int TDFXQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *, int *, int *); + +/* + * ADAPTOR INFORMATION + */ + +static XF86VideoEncodingRec OverlayEncoding[] = +{ + { 0, "XV_IMAGE", 2048, 2048, {1, 1} } +}; + +static XF86VideoEncodingRec TextureEncoding[] = +{ + { 0, "XV_IMAGE", 1024, 1024, {1, 1} } +}; + +static XF86VideoFormatRec OverlayFormats[] = +{ + {8, TrueColor}, {8, DirectColor}, {8, PseudoColor}, + {8, GrayScale}, {8, StaticGray}, {8, StaticColor}, + {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, + {15, DirectColor}, {16, DirectColor}, {24, DirectColor} +}; + +static XF86VideoFormatRec TextureFormats[] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +static XF86AttributeRec OverlayAttributes[] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"} +}; + +static XF86AttributeRec TextureAttributes[] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"} +}; + +static XF86ImageRec OverlayImages[] = +{ + XVIMAGE_YUY2, XVIMAGE_UYVY, XVIMAGE_YV12, XVIMAGE_I420 +}; + +static XF86ImageRec TextureImages[] = +{ + XVIMAGE_YV12, XVIMAGE_I420 +}; + +/* + * COMMON SETUP FUNCTIONS + */ void TDFXInitVideo(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; - XF86VideoAdaptorPtr newAdaptor = NULL; + XF86VideoAdaptorPtr newOverlayAdaptor = NULL; + XF86VideoAdaptorPtr newTextureAdaptor = NULL; TDFXPtr pTDFX = TDFXPTR(pScrn); int num_adaptors; @@ -87,685 +136,997 @@ void TDFXInitVideo(ScreenPtr pScreen) if(pTDFX->cpp == 1) return; - newAdaptor = TDFXSetupImageVideo(pScreen); - - /* Initialize the offscreen buffer */ - pTDFX->offscreenYUVBuf = 0; - + /* Start with the generic adaptors */ num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); - if(newAdaptor) { - if(!num_adaptors) { - num_adaptors = 1; - adaptors = &newAdaptor; - } else { - newAdaptors = /* need to free this someplace */ - xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); - if(newAdaptors) { - memcpy(newAdaptors, adaptors, num_adaptors * - sizeof(XF86VideoAdaptorPtr)); - newAdaptors[num_adaptors] = newAdaptor; - adaptors = newAdaptors; - num_adaptors++; - } - } + /* Overlay adaptor */ + if(pTDFX->AccelInfoRec && pTDFX->AccelInfoRec->FillSolidRects) + newOverlayAdaptor = TDFXSetupImageVideoOverlay(pScreen); + + /* Texture adaptor */ + if(pTDFX->AccelInfoRec && pTDFX->AccelInfoRec->FillSolidRects) + newTextureAdaptor = TDFXSetupImageVideoTexture(pScreen); + + /* Add the overlay adaptor to the list */ + if(newOverlayAdaptor) { + newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); + if(newAdaptors) { + if (num_adaptors) memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newOverlayAdaptor; + adaptors = newAdaptors; /* FIXME: leak? */ + num_adaptors++; + } } - if(num_adaptors) - { - xf86XVScreenInit(pScreen, adaptors, num_adaptors); + /* Add the texture adaptor to the list */ + if(newTextureAdaptor) { + newAdaptors = xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); + if(newAdaptors) { + if (num_adaptors) memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newTextureAdaptor; + adaptors = newAdaptors; /* FIXME: leak? */ + num_adaptors++; + } } + if(num_adaptors) + xf86XVScreenInit(pScreen, adaptors, num_adaptors); + if(newAdaptors) - xfree(newAdaptors); + xfree(newAdaptors); } + void TDFXCloseVideo (ScreenPtr pScreen) { - } -/* client libraries expect an encoding */ -static XF86VideoEncodingRec DummyEncoding[1] = + +static XF86VideoAdaptorPtr +TDFXAllocAdaptor(ScrnInfoPtr pScrn, int numberPorts) { - { /* blit limit */ - 0, - "XV_IMAGE", - 1024, 0, /* Height is a limitation of pixmap space, and filled in later. */ - {1, 1} - } -}; + XF86VideoAdaptorPtr adapt; + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv; + int i; -#define NUM_FORMATS_OVERLAY 3 + if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) + return NULL; -static XF86VideoFormatRec Formats[NUM_FORMATS_OVERLAY] = -{ - {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, -}; + if(!(pPriv = xcalloc(1, sizeof(TDFXPortPrivRec) + numberPorts * sizeof(DevUnion)))) + { + xfree(adapt); + return NULL; + } -/* #define NUM_IMAGES 4*/ -#define NUM_IMAGES 2 + adapt->pPortPrivates = (DevUnion*)(&pPriv[1]); + for(i = 0; i < numberPorts; i++) + adapt->pPortPrivates[i].val = i; -static XF86ImageRec Images[NUM_IMAGES] = -{ - XVIMAGE_YV12, /* YVU planar */ - XVIMAGE_I420 /* YUV planar */ -#if 0 - /* These could be supported (without a temp bufer) using the - * host-to-screen-stretch */ - XVIMAGE_YUY2, /* YUYV packed */ - XVIMAGE_UYVY /* UYVY packed */ -#endif -}; + xvColorKey = MAKE_ATOM("XV_COLORKEY"); /* FIXME: twice, leak */ + xvFilterQuality = MAKE_ATOM("XV_FILTER_QUALITY"); /* FIXME: twice, leak */ + + pPriv->colorKey = pTDFX->videoKey; + pPriv->videoStatus = 0; + pPriv->filterQuality = 1; + + return adapt; +} static XF86VideoAdaptorPtr -TDFXAllocAdaptor(ScrnInfoPtr pScrn) +TDFXSetupImageVideoOverlay(ScreenPtr pScreen) { - DevUnion *devUnions; - int i; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv; XF86VideoAdaptorPtr adapt; - if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn))) - return NULL; - /* Allocate a TDFX private structure */ - /* There is no need for a TDFX private structure at this time. But a - * DevUnion has to be provided to the core Xv code. */ - if (!(devUnions = xcalloc (1, sizeof (DevUnion) * TDFX_MAX_PORTS))) - { - xfree (adapt); - return NULL; - } - adapt->pPortPrivates = &devUnions[0]; - - /* Fill in some of the DevUnion */ - for (i = 0; i < TDFX_MAX_PORTS; i++) - { - adapt->pPortPrivates[i].val = i; - adapt->pPortPrivates[i].ptr = NULL; /* No private data */ - } - - return adapt; -} + if (!pTDFX->OverlayXvideo) + return NULL; + if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_OVERLAY_PORTS))) + return NULL; + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "3dfx Video Overlay"; + adapt->nPorts = TDFX_MAX_OVERLAY_PORTS; + adapt->nEncodings = sizeof(OverlayEncoding) / sizeof(XF86VideoEncodingRec); + adapt->pEncodings = OverlayEncoding; + adapt->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec); + adapt->pFormats = OverlayFormats; + adapt->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec); + adapt->pAttributes = OverlayAttributes; + adapt->nImages = sizeof(OverlayImages) / sizeof(XF86ImageRec); + adapt->pImages = OverlayImages; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = TDFXStopVideoOverlay; + adapt->SetPortAttribute = TDFXSetPortAttributeOverlay; + adapt->GetPortAttribute = TDFXGetPortAttributeOverlay; + adapt->QueryBestSize = TDFXQueryBestSize; + adapt->PutImage = TDFXPutImageOverlay; + adapt->QueryImageAttributes = TDFXQueryImageAttributes; -static XF86VideoAdaptorPtr -TDFXSetupImageVideo(ScreenPtr pScreen) + pPriv = (TDFXPortPrivPtr)(adapt->pPortPrivates[0].ptr); + REGION_INIT(pScreen, &(pPriv->clip), NullBox, 0); + + pTDFX->overlayAdaptor = adapt; + + TDFXResetVideoOverlay(pScrn); + + return adapt; +} + +static XF86VideoAdaptorPtr +TDFXSetupImageVideoTexture(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - XF86VideoAdaptorPtr adapt; TDFXPtr pTDFX = TDFXPTR(pScrn); + XF86VideoAdaptorPtr adapt; - DummyEncoding[0].height = pTDFX->pixmapCacheLines; + if (!pTDFX->TextureXvideo) + return NULL; - adapt = TDFXAllocAdaptor(pScrn); + if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_TEXTURE_PORTS))) + return NULL; adapt->type = XvWindowMask | XvInputMask | XvImageMask; - /* Add VIDEO_OVERLAID_IMAGES if using the overlay */ adapt->flags = 0; - adapt->name = "3dfx Accelerated Video Engine"; - adapt->nEncodings = 1; - adapt->pEncodings = &DummyEncoding[0]; - adapt->nFormats = NUM_FORMATS_OVERLAY; - adapt->pFormats = Formats; - adapt->nPorts = TDFX_MAX_PORTS; - adapt->nAttributes = 0; - adapt->pAttributes = NULL; - adapt->nImages = NUM_IMAGES; - adapt->pImages = Images; - - /* XXX For now all I'm implementing is PutImage so that programs like OMS - * will work. More will follow as I have time and need. */ + adapt->name = "3dfx Video Texture"; + adapt->nPorts = TDFX_MAX_TEXTURE_PORTS; + adapt->nEncodings = sizeof(TextureEncoding) / sizeof(XF86VideoEncodingRec); + adapt->pEncodings = TextureEncoding; + adapt->nFormats = sizeof(TextureFormats) / sizeof(XF86VideoFormatRec); + adapt->pFormats = TextureFormats; + adapt->nAttributes = sizeof(TextureAttributes) / sizeof(XF86AttributeRec); + adapt->pAttributes = TextureAttributes; + adapt->nImages = sizeof(TextureImages) / sizeof(XF86ImageRec); + adapt->pImages = TextureImages; adapt->PutVideo = NULL; adapt->PutStill = NULL; adapt->GetVideo = NULL; adapt->GetStill = NULL; - adapt->StopVideo = TDFXStopVideo; - adapt->SetPortAttribute = TDFXSetPortAttribute; - adapt->GetPortAttribute = TDFXGetPortAttribute; + adapt->StopVideo = TDFXStopVideoTexture; + adapt->SetPortAttribute = TDFXSetPortAttributeTexture; + adapt->GetPortAttribute = TDFXGetPortAttributeTexture; adapt->QueryBestSize = TDFXQueryBestSize; - adapt->PutImage = TDFXPutImage; - /*adapt->PutImage = TDFXPutImageOverlay; */ + adapt->PutImage = TDFXPutImageTexture; adapt->QueryImageAttributes = TDFXQueryImageAttributes; + pTDFX->textureAdaptor = adapt; + return adapt; } -static void -TDFXStopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) -{ - if (cleanup) - { - /* Deallocate the offscreen temporary buffer. */ - TDFXDeallocateOffscreenBuffer (pScrn, 0); - } +/* + * MISCELLANEOUS ROUTINES + */ + + +static int +TDFXQueryImageAttributes( + ScrnInfoPtr pScrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets +){ + int size, tmp; + + if(*w > 1024) *w = 1024; + if(*h > 1024) *h = 1024; + + *w = (*w + 1) & ~1; + if(offsets) offsets[0] = 0; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if(pitches) pitches[0] = size; + size *= *h; + if(offsets) offsets[1] = size; + tmp = ((*w >> 1) + 3) & ~3; + if(pitches) pitches[1] = pitches[2] = tmp; + tmp *= (*h >> 1); + size += tmp; + if(offsets) offsets[2] = size; + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if(pitches) pitches[0] = size; + size *= *h; + break; + } + + return size; } -static int -TDFXSetPortAttribute (ScrnInfoPtr pScrn, - Atom attribute, - INT32 value, - pointer data) -{ - return BadMatch; +static int +TDFXSetPortAttributeOverlay( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data +){ + + TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data; + TDFXPtr pTDFX = TDFXPTR(pScrn); + + if(attribute == xvColorKey) { + pPriv->colorKey = value; + pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey); + pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey); + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); + } else if(attribute == xvFilterQuality) { + if((value < 0) || (value > 1)) + return BadValue; + pPriv->filterQuality = value; + } else return BadMatch; + + return Success; +} + +static int +TDFXGetPortAttributeOverlay( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +){ + TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data; + + if(attribute == xvColorKey) { + *value = pPriv->colorKey; + } else if(attribute == xvFilterQuality) { + *value = pPriv->filterQuality; + } else return BadMatch; + + return Success; } static int -TDFXGetPortAttribute(ScrnInfoPtr pScrn, - Atom attribute, - INT32 *value, - pointer data) -{ - return BadMatch; +TDFXSetPortAttributeTexture( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 value, + pointer data +) { + return Success; } +static int +TDFXGetPortAttributeTexture( + ScrnInfoPtr pScrn, + Atom attribute, + INT32 *value, + pointer data +){ + return Success; +} -static void -TDFXQueryBestSize(ScrnInfoPtr pScrn, - Bool motion, - short vid_w, short vid_h, - short drw_w, short drw_h, - unsigned int *p_w, unsigned int *p_h, - pointer data) -{ - /* No alignment restrictions */ + +static void +TDFXQueryBestSize( + ScrnInfoPtr pScrn, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, + pointer data +){ + if(vid_w > drw_w) drw_w = vid_w; + if(vid_h > drw_h) drw_h = vid_h; + *p_w = drw_w; - *p_h = drw_h; + *p_h = drw_h; } - -/* This performs a screen to screen stretch blit. All coordinates are - * in screen memory. This function assumes that the src and dst format - * registers have been setup already. This function does not save - * the registers it trashes. */ static void -TDFXScreenToScreenYUVStretchBlit (ScrnInfoPtr pScrn, - short src_x1, short src_y1, - short src_x2, short src_y2, - short dst_x1, short dst_y1, - short dst_x2, short dst_y2) -{ - TDFXPtr pTDFX = TDFXPTR(pScrn); +TDFXCopyData( + unsigned char *src, + unsigned char *dst, + int srcPitch, + int dstPitch, + int h, + int w +){ + while(h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} - /* reformulate the paramaters the way the hardware wants them */ - INT32 - src_x = src_x1 & 0x1FFF, - src_y = src_y1 & 0x1FFF, - dst_x = dst_x1 & 0x1FFF, - dst_y = dst_y1 & 0x1FFF, - src_w = (src_x2 - src_x) & 0x1FFF, - src_h = (src_y2 - src_y) & 0x1FFF, - dst_w = (dst_x2 - dst_x) & 0x1FFF, - dst_h = (dst_y2 - dst_y) & 0x1FFF; - - /* Setup for blit src and dest */ - TDFXMakeRoom(pTDFX, 5); - DECLARE(SSTCP_DSTSIZE|SSTCP_SRCSIZE|SSTCP_DSTXY| - SSTCP_COMMAND|SSTCP_COMMANDEXTRA); - /* We want the blit to wait for vsync. */ - TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, 4); - TDFXWriteLong(pTDFX, SST_2D_SRCSIZE, src_w | (src_h<<16)); - TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, dst_w | (dst_h<<16)); - TDFXWriteLong(pTDFX, SST_2D_DSTXY, dst_x | (dst_y<<16)); - /* XXX find the ROP table and figure out why CC is the right choice. */ - TDFXWriteLong(pTDFX, SST_2D_COMMAND, - (0xCC<<24)|SST_2D_SCRNTOSCRNSTRETCH); - /* Write to the launch area to start the blit */ - TDFXMakeRoom(pTDFX, 1); - DECLARE_LAUNCH (1, 0); - TDFXWriteLong(pTDFX, SST_2D_LAUNCH, src_x | (src_y<<16)); +static void +TDFXCopyMungedData( + unsigned char *src1, + unsigned char *src2, + unsigned char *src3, + unsigned char *dst1, + int srcPitch, + int srcPitch2, + int dstPitch, + int h, + int w +){ + CARD32 *dst; + CARD8 *s1, *s2, *s3; + int i, j; + + w >>= 1; + + for(j = 0; j < h; j++) { + dst = (CARD32*)dst1; + s1 = src1; s2 = src2; s3 = src3; + i = w; + while(i > 4) { + dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24); + dst[1] = s1[2] | (s1[3] << 16) | (s3[1] << 8) | (s2[1] << 24); + dst[2] = s1[4] | (s1[5] << 16) | (s3[2] << 8) | (s2[2] << 24); + dst[3] = s1[6] | (s1[7] << 16) | (s3[3] << 8) | (s2[3] << 24); + dst += 4; s2 += 4; s3 += 4; s1 += 8; + i -= 4; + } + while(i--) { + dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24); + dst++; s2++; s3++; + s1 += 2; + } + + dst1 += dstPitch; + src1 += srcPitch; + if(j & 1) { + src2 += srcPitch2; + src3 += srcPitch2; + } + } } + +/* + * TEXTURE DRAWING FUNCTIONS + */ + + static void -YUVPlanarToPacked (ScrnInfoPtr pScrn, - short src_x, short src_y, - short src_h, short src_w, - int id, char *buf, - short width, short height, - FBAreaPtr fbarea) +TDFXStopVideoTexture(ScrnInfoPtr pScrn, pointer data, Bool cleanup) { TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data; - INT32 y; - void *dst; - char *psrc = buf, - *pdst = 0; - int count = 0; - - /* Register saves */ - INT32 - yuvBaseAddr, - yuvStride; - - /* Save these registers so I can restore them when we are done. */ - yuvBaseAddr = TDFXReadLongMMIO(pTDFX, YUVBASEADDR); - yuvStride = TDFXReadLongMMIO(pTDFX, YUVSTRIDE); - - - dst = 0; - - /* Set yuvBaseAddress register to point to the buffer. */ - TDFXWriteLongMMIO (pTDFX, YUVBASEADDR, pTDFX->fbOffset + - pTDFX->stride * (fbarea->box.y1 + pScrn->virtualY) - + fbarea->box.x1); - /* Set yuvStride register to reflect stride of U and V planes */ - /* There is a subtle issue involved with copying the Y plane. Y is - * sampled at twice the rate of the U and V data, in both - * directions. But when packing their needs to be two Y values for - * each U,V pair. So if src_x is odd we will end up missing on - * of the Y values. To correct for this we will always adjust the src - * x value. This adjust is done both in computing the address of the - * pixels to copy and when determining the amount of pixels to copy. - * Note that care needs to be taken to insure that the offscreen - * temporary buffer is allocated with enough space to hold the possible - * extra column of data. - */ - TDFXWriteLongMMIO (pTDFX, YUVSTRIDE, pTDFX->stride); - psrc = (char*)buf; - - /* psrc points to the base of the Y plane, move out to src_x, src_y */ - psrc += (src_x & ~0x1) + src_y * width; - pdst = (char *)pTDFX->MMIOBase[0] + YUV_Y_BASE; - for (y = 0; y < src_h; y++) - { - memcpy (pdst, psrc, src_w + (src_x & 0x1)); - psrc += width; - /* YUV planar region is always 1024 bytes wide */ - pdst += 1024; - } + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); - /* The difference between FOURCC_YV12 and FOURCC_I420 is the order - * that the U and V planes appear in the buffer. But at this point - * I just send the second buffer as V and the third buffer as U. - * Depending on the format, the packing will be different and we - * handle it in the the way we pick the source format for the blit - * later on. */ - - pdst = (char *)pTDFX->MMIOBase[0] + YUV_V_BASE; - psrc = (char*)buf + width * height; - /* psrc now points to the base of the V plane, move out to src_x/2, - * src_y/2 */ - psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1); - for (y = 0; y < src_h >> 1; y++) - { - /* YUV planar region is always 1024 bytes wide */ - memcpy (pdst, psrc, src_w >> 1); - psrc += width >> 1; - pdst += 1024; - } - pdst = (char *)pTDFX->MMIOBase[0] + YUV_U_BASE; - psrc = (char*)buf + width * height + (width >> 1) * (height >> 1); - /* psrc now points to the base of the U plane, move out to src_x/2, - * src_y/2 */ - psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1); - for (y = 0; y < src_h >> 1; y++) - { - /* YUV planar region is always 1024 bytes wide */ - memcpy (pdst, psrc, src_w >> 1); - psrc += width >> 1; - pdst += 1024; + if (cleanup) { + if(pTDFX->textureBuffer) { + xf86FreeOffscreenArea(pTDFX->textureBuffer); + pTDFX->textureBuffer = NULL; + } } +} - /* Before restoring trashed registers we have to wait for the conversion - * to finish. We aren't using the FIFO for this but the hardware can - * take a little extra time even after we finish all the writes. If we - * restore the registers before it finishes it can store some of the YUV - * data to the wrong place. One particular wrong place is often on top - * of the hardware cursor data. So we wait for the status register - * to go idle. */ - /* XXX Right now wait for the whole chip to go idle. This is more than - * is required. Find out which subsystem is handles the YUV packing and - * wait only on that status bit. */ - count = 0; - do - { - count++; - } while ((TDFXReadLongMMIO(pTDFX, 0) & SST_BUSY) && count < 1000); - - /* Restore trashed registers */ - TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, yuvBaseAddr); - TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, yuvStride); + +static void +TDFXScreenToScreenYUVStretchBlit (ScrnInfoPtr pScrn, + short src_x1, short src_y1, + short src_x2, short src_y2, + short dst_x1, short dst_y1, + short dst_x2, short dst_y2) +{ + TDFXPtr pTDFX = TDFXPTR(pScrn); + /* reformulate the paramaters the way the hardware wants them */ + INT32 src_x = src_x1 & 0x1FFF; + INT32 src_y = src_y1 & 0x1FFF; + INT32 dst_x = dst_x1 & 0x1FFF; + INT32 dst_y = dst_y1 & 0x1FFF; + INT32 src_w = (src_x2 - src_x1) & 0x1FFF; + INT32 src_h = (src_y2 - src_y1) & 0x1FFF; + INT32 dst_w = (dst_x2 - dst_x1) & 0x1FFF; + INT32 dst_h = (dst_y2 - dst_y1) & 0x1FFF; + /* Setup for blit src and dest */ + TDFXMakeRoom(pTDFX, 4); + DECLARE(SSTCP_DSTSIZE|SSTCP_SRCSIZE|SSTCP_DSTXY|SSTCP_COMMAND/*|SSTCP_COMMANDEXTRA*/); + /* TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, SST_COMMANDEXTRA_VSYNC);*/ + TDFXWriteLong(pTDFX, SST_2D_SRCSIZE, src_w | (src_h<<16)); + TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, dst_w | (dst_h<<16)); + TDFXWriteLong(pTDFX, SST_2D_DSTXY, dst_x | (dst_y<<16)); + TDFXWriteLong(pTDFX, SST_2D_COMMAND, SST_2D_SCRNTOSCRNSTRETCH | 0xCC000000); + /* Write to the launch area to start the blit */ + TDFXMakeRoom(pTDFX, 1); + DECLARE_LAUNCH(1, 0); + TDFXWriteLong(pTDFX, SST_2D_LAUNCH, (src_x<<1) | (src_y<<16)); + /* Wait for it to happen */ + TDFXSendNOPFifo2D(pScrn); } -static int -TDFXPutImage( - 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 - ) + +static void +YUVPlanarToPacked (ScrnInfoPtr pScrn, + short src_x, short src_y, + short src_h, short src_w, + int id, char *buf, + short width, short height, + FBAreaPtr fbarea) { TDFXPtr pTDFX = TDFXPTR(pScrn); + char *psrc, *pdst; + int count; + int baseaddr; + INT32 yuvBaseAddr, yuvStride; + + /* Save these registers so I can restore them when we are done. */ + yuvBaseAddr = TDFXReadLongMMIO(pTDFX, YUVBASEADDR); + yuvStride = TDFXReadLongMMIO(pTDFX, YUVSTRIDE); + + /* Set yuvBaseAddress and yuvStride. */ + baseaddr = pTDFX->fbOffset + pTDFX->cpp * fbarea->box.x1 + pTDFX->stride * fbarea->box.y1; + TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, pTDFX->stride); + TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, baseaddr); + + /* Copy Y plane (twice as much Y as U or V) */ + psrc = (char *)buf; + psrc += (src_x & ~0x1) + src_y * width; + pdst = (char *)pTDFX->MMIOBase[0] + YUV_Y_BASE; + TDFXCopyData(psrc, pdst, width, 1024, src_h, src_w + (src_x & 0x1)); + + /* Copy V plane */ + psrc = (char*)buf + width * height; + psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1); + pdst = (char *)pTDFX->MMIOBase[0] + YUV_V_BASE; + TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1); + + /* Copy U plane */ + psrc = (char*)buf + width * height + (width >> 1) * (height >> 1); + psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1); + pdst = (char *)pTDFX->MMIOBase[0] + YUV_U_BASE; + TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1); + + /* IDLE until the copy finished, timeout for safety */ + for (count = 0; count < 1000; count++) + if (!((TDFXReadLongMMIO(pTDFX, STATUS) & SST_BUSY))) + break; + + /* Restore trashed registers */ + TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, yuvBaseAddr); + TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, yuvStride); + + /* Wait for it to happen */ + TDFXSendNOPFifo2D(pScrn); +} + +static int +TDFXPutImageTexture( + 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 + ) +{ + TDFXPtr pTDFX = TDFXPTR(pScrn); BoxPtr pbox; int nbox; + int format; + + /* Check the source format */ + if (id == FOURCC_YV12) format = SST_2D_FORMAT_YUYV; + else if (id == FOURCC_UYVY) format = SST_2D_FORMAT_UYVY; + else return BadAlloc; + + /* Get a buffer to store the packed YUV data */ + if (!(pTDFX->textureBuffer = TDFXAllocateMemoryArea(pScrn, pTDFX->textureBuffer, src_w, src_h))) + return BadAlloc; + + /* Pack the YUV data in offscreen memory using YUV framebuffer (0x[CDE]0000) */ + YUVPlanarToPacked (pScrn, src_x, src_y, src_h, src_w, + id, (char *)buf, width, height, + pTDFX->textureBuffer); + + /* Setup source and destination pixel formats (yuv -> rgb) */ + TDFXMakeRoom(pTDFX, 2); + DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT); + TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->stride|((pTDFX->cpp+1)<<16)); + TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->stride|((format)<<16)); + + /* Blit packed YUV data from offscreen memory, respecting clips */ +#define SRC_X1 (pTDFX->textureBuffer->box.x1) +#define SRC_Y1 (pTDFX->textureBuffer->box.y1) +#define SCALEX(dx) ((int)(((dx) * src_w) / drw_w)) +#define SCALEY(dy) ((int)(((dy) * src_h) / drw_h)) + for (nbox = REGION_NUM_RECTS(clipBoxes), + pbox = REGION_RECTS(clipBoxes); nbox > 0; nbox--, pbox++) + { + TDFXScreenToScreenYUVStretchBlit (pScrn, + SRC_X1 + SCALEX(pbox->x1 - drw_x), + SRC_Y1 + SCALEY(pbox->y1 - drw_y), + SRC_X1 + SCALEX(pbox->x2 - drw_x), + SRC_Y1 + SCALEY(pbox->y2 - drw_y), + pbox->x1, pbox->y1, + pbox->x2, pbox->y2); + } - FBAreaPtr fbarea; + /* Restore the WAX registers we trashed */ + TDFXMakeRoom(pTDFX, 2); + DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT); + TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->sst2DDstFmtShadow); + TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->sst2DSrcFmtShadow); - /* Make sure we are synced up (this really means, lock and find the - * fifo pointer. */ - TDFXFirstSync (pScrn); + /* Wait for it to happen */ + TDFXSendNOPFifo2D(pScrn); - /* Do the right thing for the given format */ - switch (id) - { - case FOURCC_YV12: - case FOURCC_I420: - /* Get a buffer to use to store the packed YUV data */ - fbarea = TDFXAllocateOffscreenBuffer (pScrn, id, src_w, src_h); - - if (!fbarea) - { - return Success; - } + return Success; +} - YUVPlanarToPacked (pScrn, src_x, src_y, src_h, src_w, - id, (char *)buf, width, height, - fbarea); - /* Don't know what executed last so we need to send a NOP */ - TDFXSendNOP(pScrn); - - /* Setup the dst and src format once, they don't change for all the - * blits. */ - TDFXMakeRoom(pTDFX, 2); - DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT); - TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, - pTDFX->stride|((pTDFX->cpp+1)<<16)); - if (id == FOURCC_YV12) - { - /* Packed format is YUYV */ - TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, - pTDFX->stride|((SST_2D_FORMAT_YUYV)<<16)); - } - else - { - /* Packed format is UYVY */ - TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, - pTDFX->stride|((SST_2D_FORMAT_UYVY)<<16)); - } - /* Traverse the clip boxes */ - nbox = REGION_NUM_RECTS(clipBoxes); - pbox = REGION_RECTS(clipBoxes); - - while (nbox--) - { - /* The destination clip regions come with the clip boxes, but - * the src coordinates have to be computed because we are doing - * a stretch blit. These macros perform that compuation, but - * they could use some work. When testing with still images these - * computations caused some jitter in the resulting output, but - * with actual video playback I haven't noticed any problems. */ -#define SRC_X1 (fbarea->box.x1) -#define SRC_Y1 (fbarea->box.y1 + pScrn->virtualY) -#define SCALEX(dx) ((int)(((dx) * src_w + (drw_w>>1)) / drw_w)) -#define SCALEY(dy) ((int)(((dy) * src_h + (drw_h>>1)) / drw_h)) - - /* Do the screen-to-screen blit clipped to the clip boxes. */ - TDFXScreenToScreenYUVStretchBlit - (pScrn, - SRC_X1 + SCALEX(pbox->x1 - drw_x), - SRC_Y1 + SCALEY(pbox->y1 - drw_y), - SRC_X1 + SCALEX(pbox->x2 - drw_x), - SRC_Y1 + SCALEY(pbox->y2 - drw_y), - /* these destination coordinates come - * right from the clip box. */ - pbox->x1, pbox->y1, - pbox->x2, pbox->y2); - pbox++; - } +/* + * COMMON DRAWING FUNCTIONS + */ - /* Restore the WAX registers we trashed */ - TDFXMakeRoom(pTDFX, 2); - DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT); - TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->sst2DDstFmtShadow); - TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->sst2DSrcFmtShadow); +static Bool +RegionsEqual(RegionPtr A, RegionPtr B) +{ + int *dataA, *dataB; + int num; + + num = REGION_NUM_RECTS(A); + if(num != REGION_NUM_RECTS(B)) + return FALSE; + + if((A->extents.x1 != B->extents.x1) || + (A->extents.x2 != B->extents.x2) || + (A->extents.y1 != B->extents.y1) || + (A->extents.y2 != B->extents.y2)) + return FALSE; + + dataA = (int*)REGION_RECTS(A); + dataB = (int*)REGION_RECTS(B); + + while(num--) { + if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + return FALSE; + dataA += 2; + dataB += 2; + } - /* The rest of the driver won't know what I have done so I do a stall to - * make sure the next command sent will work. */ - TDFXSendNOP(pScrn); - break; - /* XXX What am I supposed to do about the sync flag? */ + return TRUE; +} - } - return Success; +static Bool +TDFXClipVideo( + BoxPtr dst, + INT32 *xa, + INT32 *xb, + INT32 *ya, + INT32 *yb, + RegionPtr reg, + INT32 width, + INT32 height +){ + INT32 vscale, hscale, delta; + BoxPtr extents = REGION_EXTENTS(DummyScreen, reg); + int diff; + + hscale = ((*xb - *xa) << 16) / (dst->x2 - dst->x1); + vscale = ((*yb - *ya) << 16) / (dst->y2 - dst->y1); + + *xa <<= 16; *xb <<= 16; + *ya <<= 16; *yb <<= 16; + + diff = extents->x1 - dst->x1; + if(diff > 0) { + dst->x1 = extents->x1; + *xa += diff * hscale; + } + diff = dst->x2 - extents->x2; + if(diff > 0) { + dst->x2 = extents->x2; + *xb -= diff * hscale; + } + diff = extents->y1 - dst->y1; + if(diff > 0) { + dst->y1 = extents->y1; + *ya += diff * vscale; + } + diff = dst->y2 - extents->y2; + if(diff > 0) { + dst->y2 = extents->y2; + *yb -= diff * vscale; + } + + if(*xa < 0) { + diff = (- *xa + hscale - 1)/ hscale; + dst->x1 += diff; + *xa += diff * hscale; + } + delta = *xb - (width << 16); + if(delta > 0) { + diff = (delta + hscale - 1)/ hscale; + dst->x2 -= diff; + *xb -= diff * hscale; + } + if(*xa >= *xb) return FALSE; + + if(*ya < 0) { + diff = (- *ya + vscale - 1)/ vscale; + dst->y1 += diff; + *ya += diff * vscale; + } + delta = *yb - (height << 16); + if(delta > 0) { + diff = (delta + vscale - 1)/ vscale; + dst->y2 -= diff; + *yb -= diff * vscale; + } + if(*ya >= *yb) return FALSE; + + if((dst->x1 != extents->x1) || (dst->x2 != extents->x2) || + (dst->y1 != extents->y1) || (dst->y2 != extents->y2)) + { + RegionRec clipReg; + REGION_INIT(DummyScreen, &clipReg, dst, 1); + REGION_INTERSECT(DummyScreen, reg, reg, &clipReg); + REGION_UNINIT(DummyScreen, &clipReg); + } + return TRUE; } -/* This code doesn't work yet. Eventually this should use the video overlay - * instead of the YUV-stretch-blit. The overlay is better because it uses - * bilinear filtering when scaling. */ -#if 0 -static int -TDFXPutImageOverlay( - 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 - ) -{ - TDFXPtr pTDFX = TDFXPTR(pScrn); - BoxPtr pbox; - int nbox; +/* + * OVERLAY DRAWING FUNCTIONS + */ - /* Computed Register values */ - INT32 - vidInFormat; - static FBAreaPtr fbarea; +static void +TDFXResetVideoOverlay(ScrnInfoPtr pScrn) +{ + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr; + + /* reset the video */ + pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK; + pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg); + pTDFX->writeLong(pTDFX, RGBMAXDELTA, 0x0080808); + pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey); + pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey); +} - /* Do the right thing for the given format */ - switch (id) - { - case FOURCC_YV12: - case FOURCC_I420: - - /* Get a buffer to use to store the packed YUV data */ - fbarea = TDFXAllocateOffscreenBuffer (pScrn, id, src_w, src_h); - - if (!fbarea) - return Success; - - YUVPlanarToPacked (pScrn, - src_x, src_y, src_h, src_w, - id, buf, width, height, - fbarea); - - /* Setup the overlay */ - TDFXWriteLongMMIO(pTDFX, VIDOVERLAYSTARTCOORDS, - (drw_x&0x7FF) | ((drw_y & 0x7FF) << 12) - /* XXX Lower 2 bits of X and Y? */); - TDFXWriteLongMMIO(pTDFX, VIDOVERLAYENDSCREENCOORDS, - ((drw_x+drw_w)&0x7FF) | (((drw_y+drw_h)&0x7FF) << 12)); - - /* Set the Video in format */ - vidInFormat = 0; - /* These magic numbers come from the spec on page 151 */ - if (id == FOURCC_YV12) - { - /* Packed format is YUYV */ - vidInFormat = 0x9 << 1; - } - else - { - /* Packed format is UYVY */ - vidInFormat = 0xA << 1; - } +static void +TDFXStopVideoOverlay(ScrnInfoPtr pScrn, pointer data, Bool cleanup) +{ + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data; - TDFXWriteLongMMIO (pTDFX, VIDINFORMAT, vidInFormat); - TDFXWriteLongMMIO (pTDFX, VIDINSTRIDE, src_w); + REGION_EMPTY(pScrn->pScreen, &pPriv->clip); - /* Use magenta as the chroma color */ - if (pTDFX->cpp == 2) - { - TDFXWriteLongMMIO(pTDFX, VIDCHROMAMIN, - 0x0000F71F); - TDFXWriteLongMMIO(pTDFX, VIDCHROMAMAX, - 0x0000F71F); + if(cleanup) { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK; + pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg); } - else /* (pTDFX->cpp == 3) */ - { - TDFXWriteLongMMIO(pTDFX, VIDCHROMAMIN, - 0x00FF00FF); - TDFXWriteLongMMIO(pTDFX, VIDCHROMAMAX, - 0x00FF00FF); + if(pTDFX->overlayBuffer) { + xf86FreeOffscreenLinear(pTDFX->overlayBuffer); + pTDFX->overlayBuffer = NULL; } - - /* Set the src address */ - TDFXWriteLongMMIO (pTDFX, VIDINADDR0, - pTDFX->fbOffset - + pTDFX->stride * (fbarea->box.y1 + pScrn->virtualY) - + fbarea->box.x1); - - /* Traverse the clip boxes */ - nbox = REGION_NUM_RECTS(clipBoxes); - pbox = REGION_RECTS(clipBoxes); - - while (nbox--) - { - pbox++; + pPriv->videoStatus = 0; + } else { + if(pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; } - break; + } +} + + +static void +TDFXDisplayVideoOverlay( + ScrnInfoPtr pScrn, + int id, + int offset, + short width, short height, + int pitch, + int left, int right, int top, + BoxPtr dstBox, + short src_w, short src_h, + short drw_w, short drw_h +){ + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr; + int dudx, dvdy; + + dudx = (src_w << 20) / drw_w; + dvdy = (src_h << 20) / drw_h; + + offset += ((left >> 16) & ~1) << 1; + left = (left & 0x0001ffff) << 3; + + pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK; + pTDFX->ModeReg.vidcfg |= 0x00000320; + + if(drw_w != src_w) pTDFX->ModeReg.vidcfg |= (1 << 14); + if(drw_h != src_h) pTDFX->ModeReg.vidcfg |= (1 << 15); + if(id == FOURCC_UYVY) pTDFX->ModeReg.vidcfg |= (6 << 21); + else pTDFX->ModeReg.vidcfg |= (5 << 21); + if(pScrn->depth == 8) pTDFX->ModeReg.vidcfg |= (1 << 11); + if(pPriv->filterQuality) pTDFX->ModeReg.vidcfg |= (3 << 16); + pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg); + + pTDFX->writeLong(pTDFX, VIDOVERLAYSTARTCOORDS, dstBox->x1 | (dstBox->y1 << 12)); + pTDFX->writeLong(pTDFX, VIDOVERLAYENDSCREENCOORDS, (dstBox->x2 - 1) | ((dstBox->y2 - 1) << 12)); + pTDFX->writeLong(pTDFX, VIDOVERLAYDUDX, dudx); + pTDFX->writeLong(pTDFX, VIDOVERLAYDUDXOFFSETSRCWIDTH, left | (src_w << 20)); + pTDFX->writeLong(pTDFX, VIDOVERLAYDVDY, dvdy); + pTDFX->writeLong(pTDFX, VIDOVERLAYDVDYOFFSET, (top & 0x0000ffff) << 3); + + pTDFX->ModeReg.stride &= 0x0000ffff; + pTDFX->ModeReg.stride |= pitch << 16; + pTDFX->writeLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE, pTDFX->ModeReg.stride); + pTDFX->writeLong(pTDFX, SST_3D_LEFTOVERLAYBUF, offset & ~3); + pTDFX->writeLong(pTDFX, VIDINADDR0, offset & ~3); +} + + +static int +TDFXPutImageOverlay( + 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 +){ + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data; + INT32 xa, xb, ya, yb; + unsigned char *dst_start; + int pitch, new_size, offset; + int s2offset = 0, s3offset = 0; + int srcPitch = 0, srcPitch2 = 0; + int dstPitch; + int top, left, npixels, nlines, bpp; + BoxRec dstBox; + CARD32 tmp; + + /* + * s2offset, s3offset - byte offsets into U and V plane of the + * source where copying starts. Y plane is + * done by editing "buf". + * + * offset - byte offset to the first line of the destination. + * + * dst_start - byte address to the first displayed pel. + * + */ + + if(src_w > drw_w) drw_w = src_w; + if(src_h > drw_h) drw_h = src_h; + + /* Clip */ + xa = src_x; + xb = src_x + src_w; + ya = src_y; + yb = 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(!TDFXClipVideo(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, width, height)) + return Success; + + dstBox.x1 -= pScrn->frameX0; + dstBox.x2 -= pScrn->frameX0; + dstBox.y1 -= pScrn->frameY0; + dstBox.y2 -= pScrn->frameY0; + + bpp = pScrn->bitsPerPixel >> 3; + pitch = bpp * pScrn->displayWidth; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + dstPitch = ((width << 1) + 3) & ~3; + new_size = ((dstPitch * height) + bpp - 1) / bpp; + srcPitch = (width + 3) & ~3; + s2offset = srcPitch * height; + srcPitch2 = ((width >> 1) + 3) & ~3; + s3offset = (srcPitch2 * (height >> 1)) + s2offset; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + dstPitch = ((width << 1) + 3) & ~3; + new_size = ((dstPitch * height) + bpp - 1) / bpp; + srcPitch = (width << 1); + break; } - return Success; + + if(!(pTDFX->overlayBuffer = TDFXAllocateMemoryLinear(pScrn, pTDFX->overlayBuffer, new_size))) + return BadAlloc; + + /* copy data */ + top = ya >> 16; + left = (xa >> 16) & ~1; + npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; + + offset = (pTDFX->overlayBuffer->offset * bpp) + (top * dstPitch) + pTDFX->fbOffset; + dst_start = pTDFX->FbBase + offset; + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + dst_start += left << 1; + tmp = ((top >> 1) * srcPitch2) + (left >> 1); + s2offset += tmp; + s3offset += tmp; + if(id == FOURCC_I420) { + tmp = s2offset; + s2offset = s3offset; + s3offset = tmp; + } + nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top; + TDFXCopyMungedData(buf + (top * srcPitch) + left, buf + s2offset, + buf + s3offset, dst_start, srcPitch, srcPitch2, + dstPitch, nlines, npixels); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + left <<= 1; + buf += (top * srcPitch) + left; + nlines = ((yb + 0xffff) >> 16) - top; + dst_start += left; + TDFXCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels << 1); + break; + } + + if(!RegionsEqual(&pPriv->clip, clipBoxes)) { + REGION_COPY(pScreen, &pPriv->clip, clipBoxes); + (*pTDFX->AccelInfoRec->FillSolidRects)(pScrn, pPriv->colorKey, + GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), + REGION_RECTS(clipBoxes)); + } + + TDFXDisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h); + + pPriv->videoStatus = CLIENT_VIDEO_ON; + + pTDFX->VideoTimerCallback = TDFXVideoTimerCallback; + + return Success; } -#endif static void -TDFXDeallocateOffscreenBuffer (ScrnInfoPtr pScrn, int id) +TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time) { - TDFXPtr pTDFX = TDFXPTR(pScrn); - - /* There is only one buffer so just deallocate it */ - if (pTDFX->offscreenYUVBuf) - xf86FreeOffscreenArea (pTDFX->offscreenYUVBuf); + TDFXPtr pTDFX = TDFXPTR(pScrn); + TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr; + + if(pPriv->videoStatus & TIMER_MASK) { + if(pPriv->videoStatus & OFF_TIMER) { + if(pPriv->offTime < time) { + pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK; + pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg); + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = time + FREE_DELAY; + } + } else + if(pPriv->videoStatus & FREE_TIMER) { + if(pPriv->freeTime < time) { + if(pTDFX->overlayBuffer) { + xf86FreeOffscreenLinear(pTDFX->overlayBuffer); + pTDFX->overlayBuffer = NULL; + } + pPriv->videoStatus = 0; + pTDFX->VideoTimerCallback = NULL; + } + } + } else /* shouldn't get here */ + pTDFX->VideoTimerCallback = NULL; } + +/* + * MEMORY MANAGEMENT + */ + + static FBAreaPtr -TDFXAllocateOffscreenBuffer (ScrnInfoPtr pScrn, int id, int width, int height) +TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height) { - int myWidth; TDFXPtr pTDFX = TDFXPTR(pScrn); + ScreenPtr pScreen; + FBAreaPtr new_area; - if (!pTDFX) - return NULL; - - /* We tweak the width slightly */ - myWidth = width; - /* We tweak the width slightly */ - myWidth = width; - - /* width is measured in pixels. The pixels in the YUV image are alway - * 8 bit YUV data. But, the xf86 offscreen manager allocates in terms of - * desktop pixels, so we adjust. */ - myWidth = myWidth / pTDFX->cpp; - if (width % pTDFX->cpp) - myWidth++; - - /* If we are putting up a subimage then we need an extra column of data - * if the source width is odd, instead of checkin the width just always - * allocate an extra column. */ - /* XXX is this really necessary? */ - myWidth++; - - if (pTDFX->offscreenYUVBuf != NULL && - myWidth == pTDFX->offscreenYUVBufWidth && - height == pTDFX->offscreenYUVBufHeight) - { - /* we already have a buffer, don't do anything. */ - return pTDFX->offscreenYUVBuf; - } - - /* We have a buffer, but its not the right size so resize it */ - if (pTDFX->offscreenYUVBuf != NULL) - { - if (!xf86ResizeOffscreenArea (pTDFX->offscreenYUVBuf, - myWidth, - height)) - { - return (NULL); - } + if (area) { + if ((area->box.x2 - area->box.x1 >= width) && + (area->box.y2 - area->box.y1 >= height)) + return area; + + if (xf86ResizeOffscreenArea(area, width, height)) + return area; + + xf86FreeOffscreenArea(area); } - else - { - /* Allocate a brand new buffer */ - pTDFX->offscreenYUVBuf = - xf86AllocateOffscreenArea (pScrn->pScreen, - myWidth, - height, - 0, - NULL, NULL, NULL); + + pScreen = screenInfo.screens[pScrn->scrnIndex]; + + new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL); + + if (!new_area) { + int max_width, max_height; + + xf86QueryLargestOffscreenArea(pScreen, &max_width, &max_height, pTDFX->cpp, 0, PRIORITY_EXTREME); + + if (max_width < width || max_height < height) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL); } - /* Return the buffer */ - pTDFX->offscreenYUVBufWidth = myWidth; - pTDFX->offscreenYUVBufHeight = height; - return (pTDFX->offscreenYUVBuf); + return new_area; } -static int -TDFXQueryImageAttributes( - ScrnInfoPtr pScrn, - int id, - unsigned short *w, unsigned short *h, - int *pitches, int *offsets) +static FBLinearPtr +TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size) { + ScreenPtr pScreen; + FBLinearPtr new_linear; - int size; - TDFXPtr pTDFX = TDFXPTR(pScrn); + if(linear) { + if(linear->size >= size) + return linear; - /* The Maximum size for 3dfx YUV planar space - * but our temporary buffer has to fit in the pixmap region which - * is the same width as the desktop and pTDFX->pixmapCacheLines - * pixels high. - */ - if(*w > 1024) *w = 1024; - if (*w > pTDFX->stride) *w = pTDFX->stride; - if(*h > pTDFX->pixmapCacheLines) *h = pTDFX->pixmapCacheLines; + if(xf86ResizeOffscreenLinear(linear, size)) + return linear; + xf86FreeOffscreenLinear(linear); + } + pScreen = screenInfo.screens[pScrn->scrnIndex]; - if (offsets) offsets[0] = 0; - switch(id) { - case FOURCC_YV12: - case FOURCC_I420: - if (pitches) pitches[0] = *w; - /* Size of Y plane plus the size of U and V planes */ - size = *w * *h; - if (offsets) offsets[1] = size; - size += ((*w >> 1) * (*h >> 1)); - if (offsets) offsets[2] = size; - size += ((*w >> 1) * (*h >> 1)); - break; - case FOURCC_UYVY: - case FOURCC_YUY2: - default: - size = *w << 1; - if(pitches) pitches[0] = size; - size *= *h; - break; - } - return size; + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL); + + if(!new_linear) { + int max_size; + + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, PRIORITY_EXTREME); + + if(max_size < size) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL); + } + + return new_linear; } #endif /* !XvExtension */ |