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