s3v_xv.c revision ba85709e
11d54945dSmrg/*
21d54945dSmrgCopyright (C) 2000 The XFree86 Project, Inc.  All Rights Reserved.
31d54945dSmrg
41d54945dSmrgPermission is hereby granted, free of charge, to any person obtaining a copy of
51d54945dSmrgthis software and associated documentation files (the "Software"), to deal in
61d54945dSmrgthe Software without restriction, including without limitation the rights to
71d54945dSmrguse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
81d54945dSmrgof the Software, and to permit persons to whom the Software is furnished to do
91d54945dSmrgso, subject to the following conditions:
101d54945dSmrg
111d54945dSmrgThe above copyright notice and this permission notice shall be included in all
121d54945dSmrgcopies or substantial portions of the Software.
131d54945dSmrg
141d54945dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
151d54945dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
161d54945dSmrgNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
171d54945dSmrgXFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
181d54945dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
191d54945dSmrgWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
201d54945dSmrg
211d54945dSmrgExcept as contained in this notice, the name of the XFree86 Project shall not
221d54945dSmrgbe used in advertising or otherwise to promote the sale, use or other dealings
231d54945dSmrgin this Software without prior written authorization from the XFree86 Project.
241d54945dSmrg*/
251d54945dSmrg
261d54945dSmrg/*
271d54945dSmrg * s3v_xv.c
281d54945dSmrg * X Video Extension support
291d54945dSmrg *
301d54945dSmrg * S3 ViRGE driver
311d54945dSmrg *
321d54945dSmrg * 7/2000 Kevin Brosius
331d54945dSmrg *
341d54945dSmrg * Useful references:
351d54945dSmrg * X Video extension support -> xc/programs/hw/xfree86/common/xf86xv.c
361d54945dSmrg *
371d54945dSmrg */
381d54945dSmrg
391d54945dSmrg#ifdef HAVE_CONFIG_H
401d54945dSmrg#include "config.h"
411d54945dSmrg#endif
421d54945dSmrg
431d54945dSmrg	/* Most xf86 commons are already in s3v.h */
441d54945dSmrg#include	"s3v.h"
451d54945dSmrg
461d54945dSmrg#if 0
471d54945dSmrg#define OFF_DELAY 	250  /* milliseconds */
481d54945dSmrg#define FREE_DELAY 	15000
491d54945dSmrg
501d54945dSmrg#define OFF_TIMER 	0x01
511d54945dSmrg#define FREE_TIMER	0x02
521d54945dSmrg#endif
531d54945dSmrg#define CLIENT_VIDEO_ON	0x04
541d54945dSmrg
551d54945dSmrg#define S3V_MAX_PORTS 1
561d54945dSmrg
571d54945dSmrg#if 0
581d54945dSmrgstatic void S3VInitOffscreenImages(ScreenPtr);
591d54945dSmrg#endif
601d54945dSmrg
611d54945dSmrgstatic XF86VideoAdaptorPtr S3VAllocAdaptor(ScrnInfoPtr pScrn);
621d54945dSmrgstatic XF86VideoAdaptorPtr S3VSetupImageVideoOverlay(ScreenPtr);
631d54945dSmrgstatic int  S3VSetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
641d54945dSmrgstatic int  S3VGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
651d54945dSmrg
66ba85709eSmrg
671d54945dSmrgstatic void S3VStopVideo(ScrnInfoPtr, pointer, Bool);
681d54945dSmrgstatic void S3VQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
691d54945dSmrg			unsigned int *, unsigned int *, pointer);
701d54945dSmrgstatic int  S3VPutImage(ScrnInfoPtr, short, short, short, short, short,
711d54945dSmrg			short, short, short, int, unsigned char*, short,
721d54945dSmrg			short, Bool, RegionPtr, pointer, DrawablePtr);
731d54945dSmrgstatic int  S3VQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
741d54945dSmrg			unsigned short *,  int *, int *);
751d54945dSmrg
761d54945dSmrg
771d54945dSmrgstatic void S3VResetVideoOverlay(ScrnInfoPtr);
781d54945dSmrg
791d54945dSmrg#if 0
801d54945dSmrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
811d54945dSmrg
821d54945dSmrgstatic Atom xvBrightness, xvContrast, xvColorKey;
831d54945dSmrg
841d54945dSmrg#endif /* 0 */
851d54945dSmrg
861d54945dSmrgint S3VQueryXvCapable(ScrnInfoPtr pScrn)
871d54945dSmrg{
881d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
891d54945dSmrg
901d54945dSmrg  if(
911d54945dSmrg     ((pScrn->bitsPerPixel == 24) ||
921d54945dSmrg      (pScrn->bitsPerPixel == 16)
931d54945dSmrg      )
941d54945dSmrg     &&
951d54945dSmrg     ((ps3v->Chipset == S3_ViRGE_DXGX)  ||
961d54945dSmrg      S3_ViRGE_MX_SERIES(ps3v->Chipset) ||
971d54945dSmrg      S3_ViRGE_GX2_SERIES(ps3v->Chipset)
981d54945dSmrg      ))
991d54945dSmrg    return TRUE;
1001d54945dSmrg  else
1011d54945dSmrg    return FALSE;
1021d54945dSmrg}
1031d54945dSmrg
1041d54945dSmrg
1051d54945dSmrgvoid S3VInitVideo(ScreenPtr pScreen)
1061d54945dSmrg{
1071d54945dSmrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1081d54945dSmrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
1091d54945dSmrg    XF86VideoAdaptorPtr newAdaptor = NULL;
1101d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
1111d54945dSmrg    int num_adaptors;
1121d54945dSmrg
1131d54945dSmrg    if(
1141d54945dSmrg       ((pScrn->bitsPerPixel == 24) ||
1151d54945dSmrg	(pScrn->bitsPerPixel == 16)
1161d54945dSmrg	)
1171d54945dSmrg       &&
1181d54945dSmrg       ((ps3v->Chipset == S3_ViRGE_DXGX)  ||
1191d54945dSmrg	S3_ViRGE_MX_SERIES(ps3v->Chipset) ||
1201d54945dSmrg	S3_ViRGE_GX2_SERIES(ps3v->Chipset) /* || */
1211d54945dSmrg	/* (ps3v->Chipset == S3_ViRGE) */
1221d54945dSmrg	)
1231d54945dSmrg       && !ps3v->NoAccel
1241d54945dSmrg       && ps3v->XVideo
1251d54945dSmrg       )
1261d54945dSmrg    {
1271d54945dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
1281d54945dSmrg	    newAdaptor = S3VSetupImageVideoOverlay(pScreen);
1291d54945dSmrg    }
1301d54945dSmrg
1311d54945dSmrg
1321d54945dSmrg    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
1331d54945dSmrg
1341d54945dSmrg    if(newAdaptor) {
1351d54945dSmrg	if(!num_adaptors) {
1361d54945dSmrg	    num_adaptors = 1;
1371d54945dSmrg	    adaptors = &newAdaptor;
1381d54945dSmrg	} else {
1391d54945dSmrg	    newAdaptors =  /* need to free this someplace */
1401d54945dSmrg		xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
1411d54945dSmrg	    if(newAdaptors) {
1421d54945dSmrg		memcpy(newAdaptors, adaptors, num_adaptors *
1431d54945dSmrg					sizeof(XF86VideoAdaptorPtr));
1441d54945dSmrg		newAdaptors[num_adaptors] = newAdaptor;
1451d54945dSmrg		adaptors = newAdaptors;
1461d54945dSmrg		num_adaptors++;
1471d54945dSmrg	    }
1481d54945dSmrg	}
1491d54945dSmrg    }
1501d54945dSmrg
1511d54945dSmrg    if(num_adaptors)
1521d54945dSmrg        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
1531d54945dSmrg
1541d54945dSmrg    if(newAdaptors)
1551d54945dSmrg	xfree(newAdaptors);
1561d54945dSmrg}
1571d54945dSmrg
1581d54945dSmrg/* client libraries expect an encoding */
1591d54945dSmrgstatic XF86VideoEncodingRec DummyEncoding[2] =
1601d54945dSmrg{
1611d54945dSmrg {   /* overlay limit */
1621d54945dSmrg   0,
1631d54945dSmrg   "XV_IMAGE",
1641d54945dSmrg   1024, 1024,
1651d54945dSmrg   {1, 1}
1661d54945dSmrg },
1671d54945dSmrg {  /* texture limit */
1681d54945dSmrg   0,
1691d54945dSmrg   "XV_IMAGE",
1701d54945dSmrg   2046, 2046,
1711d54945dSmrg   {1, 1}
1721d54945dSmrg }
1731d54945dSmrg};
1741d54945dSmrg
1751d54945dSmrg#define NUM_FORMATS_OVERLAY 4
1761d54945dSmrg#define NUM_FORMATS_TEXTURE 4
1771d54945dSmrg
1781d54945dSmrgstatic XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] =
1791d54945dSmrg{
1801d54945dSmrg  /*{15, TrueColor},*/ {16, TrueColor}, {24, TrueColor} /* ,
1811d54945dSmrg    {15, DirectColor}*/, {16, DirectColor}, {24, DirectColor}
1821d54945dSmrg};
1831d54945dSmrg
1841d54945dSmrg#if 0
1851d54945dSmrg#define NUM_ATTRIBUTES_OVERLAY 3
1861d54945dSmrg
1871d54945dSmrgstatic XF86AttributeRec Attributes[NUM_ATTRIBUTES_OVERLAY] =
1881d54945dSmrg{
1891d54945dSmrg   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
1901d54945dSmrg   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
1911d54945dSmrg   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
1921d54945dSmrg};
1931d54945dSmrg#endif
1941d54945dSmrg
1951d54945dSmrg#define NUM_IMAGES 3
1961d54945dSmrg
1971d54945dSmrgstatic XF86ImageRec Images[NUM_IMAGES] =
1981d54945dSmrg{
1991d54945dSmrg  XVIMAGE_YUY2,
2001d54945dSmrg  /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */
2011d54945dSmrg  /* copy over conversion. */
2021d54945dSmrg  XVIMAGE_YV12,
2031d54945dSmrg  XVIMAGE_I420
2041d54945dSmrg	/* XVIMAGE_UYVY */
2051d54945dSmrg};
2061d54945dSmrg
2071d54945dSmrg
2081d54945dSmrg
2091d54945dSmrgstatic int
2101d54945dSmrgS3VSetPortAttributeOverlay(
2111d54945dSmrg  ScrnInfoPtr pScrn,
2121d54945dSmrg  Atom attribute,
2131d54945dSmrg  INT32 value,
2141d54945dSmrg  pointer data
2151d54945dSmrg){
2161d54945dSmrg
2171d54945dSmrgreturn BadMatch;
2181d54945dSmrg
2191d54945dSmrg}
2201d54945dSmrg
2211d54945dSmrgstatic int
2221d54945dSmrgS3VGetPortAttributeOverlay(
2231d54945dSmrg  ScrnInfoPtr pScrn,
2241d54945dSmrg  Atom attribute,
2251d54945dSmrg  INT32 *value,
2261d54945dSmrg  pointer data
2271d54945dSmrg){
228ba85709eSmrg
2291d54945dSmrg
2301d54945dSmrgreturn BadMatch;
2311d54945dSmrg
2321d54945dSmrg}
2331d54945dSmrg
2341d54945dSmrg
2351d54945dSmrg
2361d54945dSmrgstatic void
2371d54945dSmrgS3VQueryBestSize(
2381d54945dSmrg  ScrnInfoPtr pScrn,
2391d54945dSmrg  Bool motion,
2401d54945dSmrg  short vid_w, short vid_h,
2411d54945dSmrg  short drw_w, short drw_h,
2421d54945dSmrg  unsigned int *p_w, unsigned int *p_h,
2431d54945dSmrg  pointer data
2441d54945dSmrg){
2451d54945dSmrg  *p_w = drw_w;
2461d54945dSmrg  *p_h = drw_h;
2471d54945dSmrg
2481d54945dSmrg#if 0
2491d54945dSmrg  /* Only support scaling up, no down scaling. */
2501d54945dSmrg  /* This doesn't seem to work (at least for XMovie) */
2511d54945dSmrg  /* and the DESIGN doc says this is illegal anyway... */
2521d54945dSmrg  if( drw_w < vid_w ) *p_w = vid_w;
2531d54945dSmrg  if( drw_h < vid_h ) *p_h = vid_h;
2541d54945dSmrg#endif
2551d54945dSmrg}
2561d54945dSmrg
2571d54945dSmrg
2581d54945dSmrg
2591d54945dSmrgstatic void
2601d54945dSmrgS3VResetVideoOverlay(ScrnInfoPtr pScrn)
2611d54945dSmrg{
2621d54945dSmrg  /* empty for ViRGE at the moment... */
2631d54945dSmrg#if 0
2641d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
2651d54945dSmrg  S3VPortPrivPtr pPriv = ps3v->portPrivate;
2661d54945dSmrg
2671d54945dSmrg    MGAPtr pMga = MGAPTR(pScrn);
2681d54945dSmrg    MGAPortPrivPtr pPriv = pMga->portPrivate;
2691d54945dSmrg
2701d54945dSmrg    CHECK_DMA_QUIESCENT(pMga, pScrn);
2711d54945dSmrg
2721d54945dSmrg    outMGAdac(0x51, 0x01); /* keying on */
2731d54945dSmrg    outMGAdac(0x52, 0xff); /* full mask */
2741d54945dSmrg    outMGAdac(0x53, 0xff);
2751d54945dSmrg    outMGAdac(0x54, 0xff);
2761d54945dSmrg
2771d54945dSmrg    outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
2781d54945dSmrg		    pScrn->offset.red);
2791d54945dSmrg    outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
2801d54945dSmrg		    pScrn->offset.green);
2811d54945dSmrg    outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
2821d54945dSmrg		    pScrn->offset.blue);
2831d54945dSmrg#endif
2841d54945dSmrg
2851d54945dSmrg#if 0
2861d54945dSmrg    OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
2871d54945dSmrg			       (pPriv->contrast & 0xff));
2881d54945dSmrg#endif /*0*/
2891d54945dSmrg}
2901d54945dSmrg
2911d54945dSmrg
2921d54945dSmrg
2931d54945dSmrgstatic XF86VideoAdaptorPtr
2941d54945dSmrgS3VAllocAdaptor(ScrnInfoPtr pScrn)
2951d54945dSmrg{
2961d54945dSmrg    XF86VideoAdaptorPtr adapt;
2971d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
2981d54945dSmrg    S3VPortPrivPtr pPriv;
2991d54945dSmrg    int i;
3001d54945dSmrg
3011d54945dSmrg    if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
3021d54945dSmrg	return NULL;
3031d54945dSmrg
3041d54945dSmrg    if(!(pPriv = xcalloc(1, sizeof(S3VPortPrivRec)  +
3051d54945dSmrg			(sizeof(DevUnion) * S3V_MAX_PORTS))))
3061d54945dSmrg    {
3071d54945dSmrg	xfree(adapt);
3081d54945dSmrg	return NULL;
3091d54945dSmrg    }
3101d54945dSmrg
3111d54945dSmrg    adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
3121d54945dSmrg
3131d54945dSmrg    for(i = 0; i < S3V_MAX_PORTS; i++)
3141d54945dSmrg	adapt->pPortPrivates[i].val = i;
3151d54945dSmrg
3161d54945dSmrg#if 0
3171d54945dSmrg    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
3181d54945dSmrg    xvContrast   = MAKE_ATOM("XV_CONTRAST");
3191d54945dSmrg    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
3201d54945dSmrg#endif
3211d54945dSmrg
3221d54945dSmrg    pPriv->colorKey =
3231d54945dSmrg      (1 << pScrn->offset.red) |
3241d54945dSmrg      (1 << pScrn->offset.green) |
3251d54945dSmrg      (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
3261d54945dSmrg
3271d54945dSmrg#if 0
3281d54945dSmrg    pPriv->brightness = 0;
3291d54945dSmrg    pPriv->contrast = 128;
3301d54945dSmrg#endif
3311d54945dSmrg
3321d54945dSmrg    pPriv->videoStatus = 0;
3331d54945dSmrg    pPriv->lastPort = -1;
3341d54945dSmrg
3351d54945dSmrg    ps3v->adaptor = adapt;
3361d54945dSmrg    ps3v->portPrivate = pPriv;
3371d54945dSmrg
3381d54945dSmrg    return adapt;
3391d54945dSmrg}
3401d54945dSmrg
3411d54945dSmrg
3421d54945dSmrg
3431d54945dSmrg
3441d54945dSmrg
3451d54945dSmrgstatic XF86VideoAdaptorPtr
3461d54945dSmrgS3VSetupImageVideoOverlay(ScreenPtr pScreen)
3471d54945dSmrg{
3481d54945dSmrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
3491d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
3501d54945dSmrg    XF86VideoAdaptorPtr adapt;
3511d54945dSmrg
3521d54945dSmrg    adapt = S3VAllocAdaptor(pScrn);
3531d54945dSmrg
3541d54945dSmrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
3551d54945dSmrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
3561d54945dSmrg    adapt->name = "S3 ViRGE Backend Scaler";
3571d54945dSmrg    adapt->nEncodings = 1;
3581d54945dSmrg    adapt->pEncodings = &DummyEncoding[0];
3591d54945dSmrg    adapt->nFormats = NUM_FORMATS_OVERLAY;
3601d54945dSmrg    adapt->pFormats = Formats;
3611d54945dSmrg    adapt->nPorts = 1;
3621d54945dSmrg    adapt->pAttributes = NULL /*Attributes*/;
363ba85709eSmrg    adapt->nImages = 3;
364ba85709eSmrg    adapt->nAttributes = 0;
3651d54945dSmrg    adapt->pImages = Images;
3661d54945dSmrg    adapt->PutVideo = NULL;
3671d54945dSmrg    adapt->PutStill = NULL;
3681d54945dSmrg    adapt->GetVideo = NULL;
3691d54945dSmrg    adapt->GetStill = NULL;
3701d54945dSmrg    adapt->StopVideo = S3VStopVideo;
3711d54945dSmrg    /* Empty Attrib functions - required anyway */
3721d54945dSmrg    adapt->SetPortAttribute = S3VSetPortAttributeOverlay;
3731d54945dSmrg    adapt->GetPortAttribute = S3VGetPortAttributeOverlay;
3741d54945dSmrg    adapt->QueryBestSize = S3VQueryBestSize;
3751d54945dSmrg    adapt->PutImage = S3VPutImage;
3761d54945dSmrg    adapt->QueryImageAttributes = S3VQueryImageAttributes;
3771d54945dSmrg
3781d54945dSmrg    /* gotta uninit this someplace */
3791d54945dSmrg    REGION_NULL(pScreen, &(ps3v->portPrivate->clip));
3801d54945dSmrg
3811d54945dSmrg    S3VResetVideoOverlay(pScrn);
3821d54945dSmrg
3831d54945dSmrg    return adapt;
3841d54945dSmrg}
3851d54945dSmrg
3861d54945dSmrg
3871d54945dSmrgstatic void
3881d54945dSmrgS3VStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
3891d54945dSmrg{
3901d54945dSmrg  S3VPtr ps3v = S3VPTR(pScrn);
3911d54945dSmrg  S3VPortPrivPtr pPriv = ps3v->portPrivate;
3921d54945dSmrg
3931d54945dSmrg  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
3941d54945dSmrg
3951d54945dSmrg  if(shutdown) {
3961d54945dSmrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON)
3971d54945dSmrg       {
3981d54945dSmrg	 if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
3991d54945dSmrg	      S3_ViRGE_MX_SERIES(ps3v->Chipset)
4001d54945dSmrg	      )
4011d54945dSmrg	   {
4021d54945dSmrg	     /*  Aaarg... It .. won't.. go .. away!  */
4031d54945dSmrg	     /* So let's be creative, make the overlay really */
4041d54945dSmrg	     /* small and near an edge. */
4051d54945dSmrg	     /* Size of 0 leaves a window sized vertical stripe */
4061d54945dSmrg	     /* Size of 1 leaves a single pixel.. */
4071d54945dSmrg	     OUTREG(SSTREAM_WINDOW_SIZE_REG, 1);
4081d54945dSmrg	     /* And hide it at 0,0 */
4091d54945dSmrg	     OUTREG(SSTREAM_START_REG, 0 );
4101d54945dSmrg	   }
4111d54945dSmrg	 else
4121d54945dSmrg	   {
4131d54945dSmrg	     /* Primary over secondary */
4141d54945dSmrg	     OUTREG(BLEND_CONTROL_REG, 0x01000000);
4151d54945dSmrg	   }
4161d54945dSmrg       }
4171d54945dSmrg
4181d54945dSmrg     if(pPriv->area) {
4191d54945dSmrg	xf86FreeOffscreenArea(pPriv->area);
4201d54945dSmrg	pPriv->area = NULL;
4211d54945dSmrg     }
4221d54945dSmrg     pPriv->videoStatus = 0;
4231d54945dSmrg#if 0
4241d54945dSmrg  } else {
4251d54945dSmrg     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
4261d54945dSmrg	pPriv->videoStatus |= OFF_TIMER;
4271d54945dSmrg	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
4281d54945dSmrg     }
4291d54945dSmrg#endif
4301d54945dSmrg  }
4311d54945dSmrg}
4321d54945dSmrg
4331d54945dSmrg
4341d54945dSmrg
4351d54945dSmrgstatic FBAreaPtr
4361d54945dSmrgS3VAllocateMemory(
4371d54945dSmrg   ScrnInfoPtr pScrn,
4381d54945dSmrg   FBAreaPtr area,
4391d54945dSmrg   int numlines
4401d54945dSmrg){
4411d54945dSmrg   ScreenPtr pScreen;
4421d54945dSmrg   FBAreaPtr new_area;
4431d54945dSmrg
4441d54945dSmrg   if(area) {
4451d54945dSmrg	if((area->box.y2 - area->box.y1) >= numlines)
4461d54945dSmrg	   return area;
4471d54945dSmrg
4481d54945dSmrg        if(xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines))
4491d54945dSmrg	   return area;
4501d54945dSmrg
4511d54945dSmrg	xf86FreeOffscreenArea(area);
4521d54945dSmrg   }
4531d54945dSmrg
4541d54945dSmrg   pScreen = screenInfo.screens[pScrn->scrnIndex];
4551d54945dSmrg
4561d54945dSmrg   new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
4571d54945dSmrg				numlines, 0, NULL, NULL, NULL);
4581d54945dSmrg
4591d54945dSmrg   if(!new_area) {
4601d54945dSmrg	int max_w, max_h;
4611d54945dSmrg
4621d54945dSmrg	xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
4631d54945dSmrg			FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
4641d54945dSmrg
4651d54945dSmrg	if((max_w < pScrn->displayWidth) || (max_h < numlines))
4661d54945dSmrg	   return NULL;
4671d54945dSmrg
4681d54945dSmrg	xf86PurgeUnlockedOffscreenAreas(pScreen);
4691d54945dSmrg	new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
4701d54945dSmrg				numlines, 0, NULL, NULL, NULL);
4711d54945dSmrg   }
4721d54945dSmrg
4731d54945dSmrg   return new_area;
4741d54945dSmrg}
4751d54945dSmrg
4761d54945dSmrg
4771d54945dSmrg
4781d54945dSmrgstatic void
4791d54945dSmrgS3VDisplayVideoOverlay(
4801d54945dSmrg    ScrnInfoPtr pScrn,
4811d54945dSmrg    int id,
4821d54945dSmrg    int offset,
4831d54945dSmrg    short width, short height,
4841d54945dSmrg    int pitch,
4851d54945dSmrg    /* x,y src co-ordinates */
4861d54945dSmrg    int x1, int y1, int x2, int y2,
4871d54945dSmrg    /* dst in BoxPtr format */
4881d54945dSmrg    BoxPtr dstBox,
4891d54945dSmrg    /* src width and height */
4901d54945dSmrg    short src_w, short src_h,
4911d54945dSmrg    /* dst width and height */
4921d54945dSmrg    short drw_w, short drw_h
4931d54945dSmrg){
4941d54945dSmrg    int tmp;
4951d54945dSmrg
4961d54945dSmrg#if 0
4971d54945dSmrg    CHECK_DMA_QUIESCENT(pMga, pScrn);
4981d54945dSmrg#endif
4991d54945dSmrg    S3VPtr ps3v = S3VPTR(pScrn);
5001d54945dSmrg    S3VPortPrivPtr pPriv = ps3v->portPrivate;
5011d54945dSmrg
5021d54945dSmrg  vgaHWPtr hwp = VGAHWPTR(pScrn);
5031d54945dSmrg  /*  S3VPtr ps3v = S3VPTR(pScrn);*/
5041d54945dSmrg  int vgaCRIndex, vgaCRReg, vgaIOBase;
5051d54945dSmrg  vgaIOBase = hwp->IOBase;
5061d54945dSmrg  vgaCRIndex = vgaIOBase + 4;
5071d54945dSmrg  vgaCRReg = vgaIOBase + 5;
5081d54945dSmrg
5091d54945dSmrg   /* If streams aren't enabled, do nothing */
5101d54945dSmrg   if(!ps3v->NeedSTREAMS)
5111d54945dSmrg     return;
5121d54945dSmrg
5131d54945dSmrg
5141d54945dSmrg    /* Reference at http://www.webartz.com/fourcc/ */
5151d54945dSmrg      /* Looks like ViRGE only supports YUY2 and Y211?, */
5161d54945dSmrg      /* listed as YUV-16 (4.2.2) and YUV (2.1.1) in manual. */
5171d54945dSmrg
5181d54945dSmrg#if 0
5191d54945dSmrg      /* Only supporting modes we listed for the time being, */
5201d54945dSmrg      /* No, switching required... #if 0'd this out */
5211d54945dSmrg
5221d54945dSmrg    switch(id) {
5231d54945dSmrg    case FOURCC_UYVY:
5241d54945dSmrg      /*
5251d54945dSmrg	FOURCC=0x59565955
5261d54945dSmrg	bpp=16
5271d54945dSmrg	YUV 4:2:2 (Y sample at every
5281d54945dSmrg	pixel, U and V sampled at
5291d54945dSmrg	every second pixel
5301d54945dSmrg	horizontally on each line). A
5311d54945dSmrg	macropixel contains 2 pixels
5321d54945dSmrg	in 1 u_int32.
5331d54945dSmrg      */
5341d54945dSmrg
5351d54945dSmrg      /* OUTREG(MGAREG_BESGLOBCTL, 0x000000c3 | (tmp << 16));*/
5361d54945dSmrg	 break;
5371d54945dSmrg    case FOURCC_YUY2:
5381d54945dSmrg      /*
5391d54945dSmrg	FOURCC=0x32595559
5401d54945dSmrg	bpp=16
5411d54945dSmrg	YUV 4:2:2 as for UYVY but
5421d54945dSmrg	with different component
5431d54945dSmrg	ordering within the u_int32
5441d54945dSmrg	macropixel.
5451d54945dSmrg
5461d54945dSmrg	Supports YV12 & I420 by copy over conversion of formats to YUY2,
5471d54945dSmrg	copied from mga driver.  Thanks Mark!
5481d54945dSmrg       */
5491d54945dSmrg    default:
5501d54945dSmrg      /*OUTREG(MGAREG_BESGLOBCTL, 0x00000083 | (tmp << 16));*/
5511d54945dSmrg      /* YUV-16 (4.2.2) Secondary stream */
5521d54945dSmrg      /* temp ... add DDA Horiz Accum. */
5531d54945dSmrg      /*OUTREG(SSTREAM_CONTROL_REG, 0x02000000); / YUV-16 */
5541d54945dSmrg      /* works for xvtest and suzi */
5551d54945dSmrg      /* OUTREG(SSTREAM_CONTROL_REG, 0x01000000);  * YCbCr-16 * no scaling */
5561d54945dSmrg
5571d54945dSmrg      /* calc horizontal scale factor */
5581d54945dSmrg      tmp = drw_w / src_w;
5591d54945dSmrg      if (drw_w == src_w) tmp = 0;
5601d54945dSmrg      else if (tmp>=4) tmp =3;
5611d54945dSmrg      else if (tmp>=2) tmp =2;
5621d54945dSmrg      else tmp =1;
5631d54945dSmrg
5641d54945dSmrg      /* YCbCr-16 */
5651d54945dSmrg      OUTREG(SSTREAM_CONTROL_REG,
5661d54945dSmrg	     tmp << 28 | 0x01000000 |
5671d54945dSmrg	     ((((src_w-1)<<1)-(drw_w-1)) & 0xfff)
5681d54945dSmrg	     );
5691d54945dSmrg      break;
5701d54945dSmrg    }
5711d54945dSmrg#endif
5721d54945dSmrg
5731d54945dSmrg      /* calc horizontal scale factor */
5741d54945dSmrg      if (drw_w == src_w)
5751d54945dSmrg	tmp = 0;
5761d54945dSmrg      else
5771d54945dSmrg	tmp =2;
5781d54945dSmrg      /* YCbCr-16 */
5791d54945dSmrg    OUTREG(SSTREAM_CONTROL_REG,
5801d54945dSmrg	   tmp << 28 | 0x01000000 |
5811d54945dSmrg	   ((((src_w-1)<<1)-(drw_w-1)) & 0xfff)
5821d54945dSmrg	   );
5831d54945dSmrg
5841d54945dSmrg    OUTREG(SSTREAM_STRETCH_REG,
5851d54945dSmrg	   ((src_w - 1) & 0x7ff) | (((src_w-drw_w-1) & 0x7ff) << 16)
5861d54945dSmrg	   );
5871d54945dSmrg
5881d54945dSmrg    /* Color key on primary */
5891d54945dSmrg    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
5901d54945dSmrg	 S3_ViRGE_MX_SERIES(ps3v->Chipset)
5911d54945dSmrg	 )
5921d54945dSmrg      {
5931d54945dSmrg	/* 100% of secondary, no primary */
5941d54945dSmrg	/* gx2/mx can both blend while keying, need to */
5951d54945dSmrg	/* select secondary here, otherwise all you'll get */
5961d54945dSmrg	/* from the primary is the color key.  (And setting */
5971d54945dSmrg	/* 0 here gives you black... no primary or secondary. */
5981d54945dSmrg	/* Discovered that the hard way!) */
5991d54945dSmrg	OUTREG(BLEND_CONTROL_REG, 0x20 );
6001d54945dSmrg      }
6011d54945dSmrg    else
6021d54945dSmrg      {
6031d54945dSmrg	OUTREG(BLEND_CONTROL_REG, 0x05000000);
6041d54945dSmrg      }
6051d54945dSmrg
6061d54945dSmrg    OUTREG(SSTREAM_FBADDR0_REG, offset & 0x3fffff );
6071d54945dSmrg    OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
6081d54945dSmrg
6091d54945dSmrg    OUTREG(K1_VSCALE_REG, src_h-1 );
6101d54945dSmrg    OUTREG(K2_VSCALE_REG, (src_h - drw_h) & 0x7ff );
6111d54945dSmrg
6121d54945dSmrg    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
6131d54945dSmrg	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
6141d54945dSmrg      {
6151d54945dSmrg	/* enable vert interp. & bandwidth saving - gx2 */
6161d54945dSmrg	OUTREG(DDA_VERT_REG, (((~drw_h)-1) & 0xfff ) |
6171d54945dSmrg	       /* bw & vert interp */
6181d54945dSmrg	       0xc000
6191d54945dSmrg	       /* no bw save 0x8000*/
6201d54945dSmrg	       );
6211d54945dSmrg      }
6221d54945dSmrg    else
6231d54945dSmrg      {
6241d54945dSmrg	OUTREG(DDA_VERT_REG, (((~drw_h)-1)) & 0xfff );
6251d54945dSmrg      }
6261d54945dSmrg
6271d54945dSmrg    OUTREG(SSTREAM_START_REG, ((dstBox->x1 +1) << 16) | (dstBox->y1 +1));
6281d54945dSmrg    OUTREG(SSTREAM_WINDOW_SIZE_REG,
6291d54945dSmrg	   ( ((drw_w-1) << 16) | (drw_h ) ) & 0x7ff07ff
6301d54945dSmrg	   );
6311d54945dSmrg
6321d54945dSmrg    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
6331d54945dSmrg	 S3_ViRGE_MX_SERIES(ps3v->Chipset)
6341d54945dSmrg	 )
6351d54945dSmrg      {
6361d54945dSmrg	OUTREG(COL_CHROMA_KEY_CONTROL_REG,
6371d54945dSmrg	       /* color key ON - keying on primary */
6381d54945dSmrg	       0x40000000  |
6391d54945dSmrg	       /* # bits to compare */
6401d54945dSmrg	       ((pScrn->weight.red-1) << 24) |
6411d54945dSmrg
6421d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
6431d54945dSmrg	       (16 + 8-pScrn->weight.red) |
6441d54945dSmrg
6451d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
6461d54945dSmrg	       (8 + 8-pScrn->weight.green) |
6471d54945dSmrg
6481d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
6491d54945dSmrg	       (8-pScrn->weight.blue)
6501d54945dSmrg	       );
6511d54945dSmrg      }
6521d54945dSmrg    else
6531d54945dSmrg      {
6541d54945dSmrg	OUTREG(COL_CHROMA_KEY_CONTROL_REG,
6551d54945dSmrg	       /* color key ON */
6561d54945dSmrg	       0x10000000 |
6571d54945dSmrg	       /* # bits to compare */
6581d54945dSmrg	       ((pScrn->weight.red-1) << 24) |
6591d54945dSmrg
6601d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
6611d54945dSmrg	       (16 + 8-pScrn->weight.red) |
6621d54945dSmrg
6631d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
6641d54945dSmrg	       (8 + 8-pScrn->weight.green) |
6651d54945dSmrg
6661d54945dSmrg	       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
6671d54945dSmrg	       (8-pScrn->weight.blue)
6681d54945dSmrg	       );
6691d54945dSmrg      }
6701d54945dSmrg
6711d54945dSmrg    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
6721d54945dSmrg	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
6731d54945dSmrg      {
6741d54945dSmrg	VGAOUT8(vgaCRIndex, 0x92);
6751d54945dSmrg	VGAOUT8(vgaCRReg, (((pitch + 7) / 8) >> 8) | 0x80);
6761d54945dSmrg	VGAOUT8(vgaCRIndex, 0x93);
6771d54945dSmrg	VGAOUT8(vgaCRReg, (pitch + 7) / 8);
6781d54945dSmrg      }
6791d54945dSmrg
6801d54945dSmrg}
6811d54945dSmrg
6821d54945dSmrg
6831d54945dSmrgstatic int
6841d54945dSmrgS3VPutImage(
6851d54945dSmrg  ScrnInfoPtr pScrn,
6861d54945dSmrg  short src_x, short src_y,
6871d54945dSmrg  short drw_x, short drw_y,
6881d54945dSmrg  short src_w, short src_h,
6891d54945dSmrg  short drw_w, short drw_h,
6901d54945dSmrg  int id, unsigned char* buf,
6911d54945dSmrg  short width, short height,
6921d54945dSmrg  Bool sync,
6931d54945dSmrg  RegionPtr clipBoxes, pointer data,
6941d54945dSmrg  DrawablePtr pDraw
6951d54945dSmrg){
6961d54945dSmrg   S3VPtr ps3v = S3VPTR(pScrn);
6971d54945dSmrg   S3VPortPrivPtr pPriv = ps3v->portPrivate;
6981d54945dSmrg   INT32 x1, x2, y1, y2;
6991d54945dSmrg   unsigned char *dst_start;
7001d54945dSmrg   int pitch, new_h, offset, offset2=0, offset3=0;
7011d54945dSmrg   int srcPitch, srcPitch2=0, dstPitch;
7021d54945dSmrg   int top, left, npixels, nlines;
7031d54945dSmrg   BoxRec dstBox;
7041d54945dSmrg   CARD32 tmp;
7051d54945dSmrg
7061d54945dSmrg   /* If streams aren't enabled, do nothing */
7071d54945dSmrg   if(!ps3v->NeedSTREAMS)
7081d54945dSmrg     return Success;
7091d54945dSmrg
7101d54945dSmrg   /* Clip */
7111d54945dSmrg   x1 = src_x;
7121d54945dSmrg   x2 = src_x + src_w;
7131d54945dSmrg   y1 = src_y;
7141d54945dSmrg   y2 = src_y + src_h;
7151d54945dSmrg
7161d54945dSmrg   dstBox.x1 = drw_x;
7171d54945dSmrg   dstBox.x2 = drw_x + drw_w;
7181d54945dSmrg   dstBox.y1 = drw_y;
7191d54945dSmrg   dstBox.y2 = drw_y + drw_h;
7201d54945dSmrg
7211d54945dSmrg   if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
7221d54945dSmrg			     clipBoxes, width, height))
7231d54945dSmrg	return Success;
7241d54945dSmrg
7251d54945dSmrg   /*if(!pMga->TexturedVideo) {*/
7261d54945dSmrg	dstBox.x1 -= pScrn->frameX0;
7271d54945dSmrg	dstBox.x2 -= pScrn->frameX0;
7281d54945dSmrg	dstBox.y1 -= pScrn->frameY0;
7291d54945dSmrg	dstBox.y2 -= pScrn->frameY0;
7301d54945dSmrg	/*}*/
7311d54945dSmrg
7321d54945dSmrg   pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
7331d54945dSmrg
7341d54945dSmrg   dstPitch = ((width << 1) + 15) & ~15;
7351d54945dSmrg   new_h = ((dstPitch * height) + pitch - 1) / pitch;
7361d54945dSmrg
7371d54945dSmrg   switch(id) {
7381d54945dSmrg   case FOURCC_YV12:
7391d54945dSmrg   case FOURCC_I420:
7401d54945dSmrg	srcPitch = (width + 3) & ~3;
7411d54945dSmrg	offset2 = srcPitch * height;
7421d54945dSmrg	srcPitch2 = ((width >> 1) + 3) & ~3;
7431d54945dSmrg	offset3 = (srcPitch2 * (height >> 1)) + offset2;
7441d54945dSmrg	break;
7451d54945dSmrg   case FOURCC_UYVY:
7461d54945dSmrg   case FOURCC_YUY2:
7471d54945dSmrg   default:
7481d54945dSmrg	srcPitch = (width << 1);
7491d54945dSmrg	break;
7501d54945dSmrg   }
7511d54945dSmrg
7521d54945dSmrg   if(!(pPriv->area = S3VAllocateMemory(pScrn, pPriv->area, new_h)))
7531d54945dSmrg	return BadAlloc;
7541d54945dSmrg
7551d54945dSmrg    /* copy data */
7561d54945dSmrg    top = y1 >> 16;
7571d54945dSmrg    left = (x1 >> 16) & ~1;
7581d54945dSmrg    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
7591d54945dSmrg    left <<= 1;
7601d54945dSmrg
7611d54945dSmrg    offset = pPriv->area->box.y1 * pitch;
7621d54945dSmrg    dst_start = ps3v->FBStart + offset + left + (top * dstPitch);
7631d54945dSmrg    /*dst_start = pMga->FbStart + offset + left + (top * dstPitch);*/
7641d54945dSmrg
7651d54945dSmrg
7661d54945dSmrg    switch(id) {
7671d54945dSmrg    case FOURCC_YV12:
7681d54945dSmrg    case FOURCC_I420:
7691d54945dSmrg	top &= ~1;
7701d54945dSmrg	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
7711d54945dSmrg	offset2 += tmp;
7721d54945dSmrg	offset3 += tmp;
7731d54945dSmrg	if(id == FOURCC_I420) {
7741d54945dSmrg	   tmp = offset2;
7751d54945dSmrg	   offset2 = offset3;
7761d54945dSmrg	   offset3 = tmp;
7771d54945dSmrg	}
7781d54945dSmrg	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
7791d54945dSmrg	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
7801d54945dSmrg				buf + offset2, buf + offset3, dst_start,
7811d54945dSmrg				srcPitch, srcPitch2, dstPitch, nlines, npixels);
7821d54945dSmrg	break;
7831d54945dSmrg    case FOURCC_UYVY:
7841d54945dSmrg    case FOURCC_YUY2:
7851d54945dSmrg    default:
7861d54945dSmrg	buf += (top * srcPitch) + left;
7871d54945dSmrg	nlines = ((y2 + 0xffff) >> 16) - top;
7881d54945dSmrg	xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
7891d54945dSmrg        break;
7901d54945dSmrg    }
7911d54945dSmrg
792ba85709eSmrg
7931d54945dSmrg    /* update cliplist */
7941d54945dSmrg	if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
7951d54945dSmrg	    REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
7961d54945dSmrg	    /* draw these */
7971d54945dSmrg	    xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
7981d54945dSmrg	}
7991d54945dSmrg
8001d54945dSmrg	offset += left + (top * dstPitch);
8011d54945dSmrg	S3VDisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
8021d54945dSmrg	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
8031d54945dSmrg
8041d54945dSmrg	pPriv->videoStatus = CLIENT_VIDEO_ON;
805ba85709eSmrg
8061d54945dSmrg
8071d54945dSmrg    return Success;
8081d54945dSmrg}
8091d54945dSmrg
8101d54945dSmrg
8111d54945dSmrgstatic int
8121d54945dSmrgS3VQueryImageAttributes(
8131d54945dSmrg    ScrnInfoPtr pScrn,
8141d54945dSmrg    int id,
8151d54945dSmrg    unsigned short *w, unsigned short *h,
8161d54945dSmrg    int *pitches, int *offsets
8171d54945dSmrg){
818ba85709eSmrg
8191d54945dSmrg    int size, tmp;
8201d54945dSmrg
8211d54945dSmrg	if(*w > 1024) *w = 1024;
8221d54945dSmrg	if(*h > 1024) *h = 1024;
8231d54945dSmrg
8241d54945dSmrg    *w = (*w + 1) & ~1;
8251d54945dSmrg    if(offsets) offsets[0] = 0;
8261d54945dSmrg
8271d54945dSmrg    switch(id) {
8281d54945dSmrg    case FOURCC_YV12:
8291d54945dSmrg    case FOURCC_I420:
8301d54945dSmrg	*h = (*h + 1) & ~1;
8311d54945dSmrg	size = (*w + 3) & ~3;
8321d54945dSmrg	if(pitches) pitches[0] = size;
8331d54945dSmrg	size *= *h;
8341d54945dSmrg	if(offsets) offsets[1] = size;
8351d54945dSmrg	tmp = ((*w >> 1) + 3) & ~3;
8361d54945dSmrg	if(pitches) pitches[1] = pitches[2] = tmp;
8371d54945dSmrg	tmp *= (*h >> 1);
8381d54945dSmrg	size += tmp;
8391d54945dSmrg	if(offsets) offsets[2] = size;
8401d54945dSmrg	size += tmp;
8411d54945dSmrg	break;
8421d54945dSmrg    case FOURCC_UYVY:
8431d54945dSmrg    case FOURCC_YUY2:
8441d54945dSmrg    default:
8451d54945dSmrg	size = *w << 1;
8461d54945dSmrg	if(pitches) pitches[0] = size;
8471d54945dSmrg	size *= *h;
8481d54945dSmrg	break;
8491d54945dSmrg    }
8501d54945dSmrg
8511d54945dSmrg    return size;
8521d54945dSmrg}
853