summaryrefslogtreecommitdiff
path: root/src/mga_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mga_video.c')
-rw-r--r--src/mga_video.c1280
1 files changed, 1280 insertions, 0 deletions
diff --git a/src/mga_video.c b/src/mga_video.c
new file mode 100644
index 0000000..d2e98a3
--- /dev/null
+++ b/src/mga_video.c
@@ -0,0 +1,1280 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/mga/mga_video.c,v 1.29 2001/12/26 14:54:04 dawes Exp $ */
+
+#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 "mga_bios.h"
+#include "mga_reg.h"
+#include "mga.h"
+#include "mga_macros.h"
+#include "xf86xv.h"
+#include "Xv.h"
+#include "xaa.h"
+#include "xaalocal.h"
+#include "dixstruct.h"
+#include "fourcc.h"
+
+#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 MGA_MAX_PORTS 32
+
+#ifndef XvExtension
+void MGAInitVideo(ScreenPtr pScreen) {}
+#else
+
+static void MGAInitOffscreenImages(ScreenPtr);
+
+static XF86VideoAdaptorPtr MGASetupImageVideoOverlay(ScreenPtr);
+static int MGASetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
+static int MGAGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
+
+static XF86VideoAdaptorPtr MGASetupImageVideoTexture(ScreenPtr);
+static int MGASetPortAttributeTexture(ScrnInfoPtr, Atom, INT32, pointer);
+static int MGAGetPortAttributeTexture(ScrnInfoPtr, Atom ,INT32 *, pointer);
+
+static void MGAStopVideo(ScrnInfoPtr, pointer, Bool);
+static void MGAQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
+ unsigned int *, unsigned int *, pointer);
+static int MGAPutImage(ScrnInfoPtr, short, short, short, short, short,
+ short, short, short, int, unsigned char*, short,
+ short, Bool, RegionPtr, pointer);
+static int MGAQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
+ unsigned short *, int *, int *);
+
+
+static void MGAResetVideoOverlay(ScrnInfoPtr);
+
+static void MGAVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
+
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvBrightness, xvContrast, xvColorKey, xvDoubleBuffer;
+
+void MGAInitVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ MGAPtr pMga = MGAPTR(pScrn);
+ int num_adaptors;
+
+ if((pScrn->bitsPerPixel != 8) && !pMga->NoAccel &&
+ (pMga->SecondCrtc == FALSE) &&
+ ((pMga->Chipset == PCI_CHIP_MGAG200) ||
+ (pMga->Chipset == PCI_CHIP_MGAG200_PCI) ||
+ (pMga->Chipset == PCI_CHIP_MGAG400) ||
+ (pMga->Chipset == PCI_CHIP_MGAG550)))
+ {
+ if((pMga->Overlay8Plus24 || pMga->TexturedVideo) &&
+ (pScrn->bitsPerPixel != 24))
+ {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using texture video\n");
+ newAdaptor = MGASetupImageVideoTexture(pScreen);
+ pMga->TexturedVideo = TRUE;
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
+ newAdaptor = MGASetupImageVideoOverlay(pScreen);
+ pMga->TexturedVideo = FALSE;
+ }
+ if(!pMga->Overlay8Plus24)
+ MGAInitOffscreenImages(pScreen);
+ }
+
+ 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++;
+ }
+ }
+ }
+
+ if(num_adaptors)
+ xf86XVScreenInit(pScreen, adaptors, num_adaptors);
+
+ if(newAdaptors)
+ xfree(newAdaptors);
+}
+
+/* client libraries expect an encoding */
+static XF86VideoEncodingRec DummyEncoding[2] =
+{
+ { /* overlay limit */
+ 0,
+ "XV_IMAGE",
+ 1024, 1024,
+ {1, 1}
+ },
+ { /* texture limit */
+ 0,
+ "XV_IMAGE",
+ 2046, 2046,
+ {1, 1}
+ }
+};
+
+#define NUM_FORMATS 6
+
+static XF86VideoFormatRec Formats[NUM_FORMATS] =
+{
+ {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
+ {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
+};
+
+#define NUM_ATTRIBUTES_OVERLAY 4
+
+static XF86AttributeRec Attributes[NUM_ATTRIBUTES_OVERLAY] =
+{
+ {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
+ {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
+ {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
+ {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
+};
+
+#define NUM_IMAGES 4
+
+static XF86ImageRec Images[NUM_IMAGES] =
+{
+ XVIMAGE_YUY2,
+ XVIMAGE_YV12,
+ XVIMAGE_I420,
+ XVIMAGE_UYVY
+};
+
+static void
+MGAResetVideoOverlay(ScrnInfoPtr pScrn)
+{
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+
+ CHECK_DMA_QUIESCENT(pMga, pScrn);
+
+ outMGAdac(0x51, 0x01); /* keying on */
+ outMGAdac(0x52, 0xff); /* full mask */
+ outMGAdac(0x53, 0xff);
+ outMGAdac(0x54, 0xff);
+
+ outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
+ pScrn->offset.red);
+ outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
+ pScrn->offset.green);
+ outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
+ pScrn->offset.blue);
+
+ OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
+ (pPriv->contrast & 0xff));
+}
+
+
+static XF86VideoAdaptorPtr
+MGAAllocAdaptor(ScrnInfoPtr pScrn, Bool doublebuffer)
+{
+ XF86VideoAdaptorPtr adapt;
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv;
+ int i;
+
+ if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
+ return NULL;
+
+ if(!(pPriv = xcalloc(1, sizeof(MGAPortPrivRec) +
+ (sizeof(DevUnion) * MGA_MAX_PORTS))))
+ {
+ xfree(adapt);
+ return NULL;
+ }
+
+ adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
+
+ for(i = 0; i < MGA_MAX_PORTS; i++)
+ adapt->pPortPrivates[i].val = i;
+
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvContrast = MAKE_ATOM("XV_CONTRAST");
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
+
+ pPriv->colorKey = pMga->videoKey;
+ pPriv->videoStatus = 0;
+ pPriv->brightness = 0;
+ pPriv->contrast = 128;
+ pPriv->lastPort = -1;
+ pPriv->doubleBuffer = doublebuffer;
+ pPriv->currentBuffer = 0;
+
+ pMga->adaptor = adapt;
+ pMga->portPrivate = pPriv;
+
+ return adapt;
+}
+
+static XF86VideoAdaptorPtr
+MGASetupImageVideoOverlay(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ MGAPtr pMga = MGAPTR(pScrn);
+ XF86VideoAdaptorPtr adapt;
+
+ adapt = MGAAllocAdaptor(pScrn, TRUE);
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adapt->name = "Matrox G-Series Backend Scaler";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = &DummyEncoding[0];
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = Formats;
+ adapt->nPorts = 1;
+ adapt->pAttributes = Attributes;
+ if (pMga->Chipset == PCI_CHIP_MGAG400 ||
+ pMga->Chipset == PCI_CHIP_MGAG550) {
+ adapt->nImages = 4;
+ adapt->nAttributes = 4;
+ } else {
+ adapt->nImages = 3;
+ adapt->nAttributes = 1;
+ }
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = MGAStopVideo;
+ adapt->SetPortAttribute = MGASetPortAttributeOverlay;
+ adapt->GetPortAttribute = MGAGetPortAttributeOverlay;
+ adapt->QueryBestSize = MGAQueryBestSize;
+ adapt->PutImage = MGAPutImage;
+ adapt->QueryImageAttributes = MGAQueryImageAttributes;
+
+ /* gotta uninit this someplace */
+ REGION_INIT(pScreen, &(pMga->portPrivate->clip), NullBox, 0);
+
+ MGAResetVideoOverlay(pScrn);
+
+ return adapt;
+}
+
+
+static XF86VideoAdaptorPtr
+MGASetupImageVideoTexture(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ XF86VideoAdaptorPtr adapt;
+ MGAPtr pMga = MGAPTR(pScrn);
+
+ adapt = MGAAllocAdaptor(pScrn, FALSE);
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = 0;
+ adapt->name = "Matrox G-Series Texture Engine";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = &DummyEncoding[1];
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = Formats;
+ adapt->nPorts = MGA_MAX_PORTS;
+ adapt->pAttributes = NULL;
+ adapt->nAttributes = 0;
+ adapt->pImages = Images;
+ if (pMga->Chipset == PCI_CHIP_MGAG400 ||
+ pMga->Chipset == PCI_CHIP_MGAG550)
+ adapt->nImages = 4;
+ else
+ adapt->nImages = 3;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = MGAStopVideo;
+ adapt->SetPortAttribute = MGASetPortAttributeTexture;
+ adapt->GetPortAttribute = MGAGetPortAttributeTexture;
+ adapt->QueryBestSize = MGAQueryBestSize;
+ adapt->PutImage = MGAPutImage;
+ adapt->QueryImageAttributes = MGAQueryImageAttributes;
+
+ return adapt;
+}
+
+
+
+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;
+ }
+
+ return TRUE;
+}
+
+
+/* MGAClipVideo -
+
+ Takes the dst box in standard X BoxRec form (top and left
+ edges inclusive, bottom and right exclusive). The new dst
+ box is returned. The source boundaries are given (x1, y1
+ inclusive, x2, y2 exclusive) and returned are the new source
+ boundaries in 16.16 fixed point.
+*/
+
+#define DummyScreen screenInfo.screens[0]
+
+static Bool
+MGAClipVideo(
+ BoxPtr dst,
+ INT32 *x1,
+ INT32 *x2,
+ INT32 *y1,
+ INT32 *y2,
+ RegionPtr reg,
+ INT32 width,
+ INT32 height
+){
+ INT32 vscale, hscale, delta;
+ BoxPtr extents = REGION_EXTENTS(DummyScreen, reg);
+ int diff;
+
+ hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
+ vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
+
+ *x1 <<= 16; *x2 <<= 16;
+ *y1 <<= 16; *y2 <<= 16;
+
+ diff = extents->x1 - dst->x1;
+ if(diff > 0) {
+ dst->x1 = extents->x1;
+ *x1 += diff * hscale;
+ }
+ diff = dst->x2 - extents->x2;
+ if(diff > 0) {
+ dst->x2 = extents->x2;
+ *x2 -= diff * hscale;
+ }
+ diff = extents->y1 - dst->y1;
+ if(diff > 0) {
+ dst->y1 = extents->y1;
+ *y1 += diff * vscale;
+ }
+ diff = dst->y2 - extents->y2;
+ if(diff > 0) {
+ dst->y2 = extents->y2;
+ *y2 -= diff * vscale;
+ }
+
+ if(*x1 < 0) {
+ diff = (- *x1 + hscale - 1)/ hscale;
+ dst->x1 += diff;
+ *x1 += diff * hscale;
+ }
+ delta = *x2 - (width << 16);
+ if(delta > 0) {
+ diff = (delta + hscale - 1)/ hscale;
+ dst->x2 -= diff;
+ *x2 -= diff * hscale;
+ }
+ if(*x1 >= *x2) return FALSE;
+
+ if(*y1 < 0) {
+ diff = (- *y1 + vscale - 1)/ vscale;
+ dst->y1 += diff;
+ *y1 += diff * vscale;
+ }
+ delta = *y2 - (height << 16);
+ if(delta > 0) {
+ diff = (delta + vscale - 1)/ vscale;
+ dst->y2 -= diff;
+ *y2 -= diff * vscale;
+ }
+ if(*y1 >= *y2) 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;
+}
+
+static void
+MGAStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+
+ if(pMga->TexturedVideo) return;
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+ if(shutdown) {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON)
+ OUTREG(MGAREG_BESCTL, 0);
+ if(pPriv->linear) {
+ xf86FreeOffscreenLinear(pPriv->linear);
+ pPriv->linear = NULL;
+ }
+ pPriv->videoStatus = 0;
+ } else {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ pPriv->videoStatus |= OFF_TIMER;
+ pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+ }
+ }
+}
+
+static int
+MGASetPortAttributeOverlay(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value,
+ pointer data
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+
+ CHECK_DMA_QUIESCENT(pMga, pScrn);
+
+ if(attribute == xvBrightness) {
+ if((value < -128) || (value > 127))
+ return BadValue;
+ pPriv->brightness = value;
+ OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
+ (pPriv->contrast & 0xff));
+ } else
+ if(attribute == xvContrast) {
+ if((value < 0) || (value > 255))
+ return BadValue;
+ pPriv->contrast = value;
+ OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
+ (pPriv->contrast & 0xff));
+ } else
+ if(attribute == xvColorKey) {
+ pPriv->colorKey = value;
+ outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
+ pScrn->offset.red);
+ outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
+ pScrn->offset.green);
+ outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
+ pScrn->offset.blue);
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ } else
+ if(attribute == xvDoubleBuffer) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->doubleBuffer = value;
+ } else return BadMatch;
+
+ return Success;
+}
+
+static int
+MGAGetPortAttributeOverlay(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+
+ if(attribute == xvBrightness) {
+ *value = pPriv->brightness;
+ } else
+ if(attribute == xvContrast) {
+ *value = pPriv->contrast;
+ } else
+ if(attribute == xvDoubleBuffer) {
+ *value = pPriv->doubleBuffer ? 1 : 0;
+ } else
+ if(attribute == xvColorKey) {
+ *value = pPriv->colorKey;
+ } else return BadMatch;
+
+ return Success;
+}
+
+
+static int
+MGASetPortAttributeTexture(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value,
+ pointer data
+) {
+ return BadMatch;
+}
+
+
+static int
+MGAGetPortAttributeTexture(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data
+){
+ return BadMatch;
+}
+
+static void
+MGAQueryBestSize(
+ 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
+){
+ *p_w = drw_w;
+ *p_h = drw_h;
+}
+
+
+static void
+MGACopyData(
+ unsigned char *src,
+ unsigned char *dst,
+ int srcPitch,
+ int dstPitch,
+ int h,
+ int w
+){
+ w <<= 1;
+ while(h--) {
+ memcpy(dst, src, w);
+ src += srcPitch;
+ dst += dstPitch;
+ }
+}
+
+static void
+MGACopyMungedData(
+ 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;
+ }
+ }
+}
+
+
+static FBLinearPtr
+MGAAllocateMemory(
+ ScrnInfoPtr pScrn,
+ FBLinearPtr linear,
+ int size
+){
+ ScreenPtr pScreen;
+ FBLinearPtr new_linear;
+
+ if(linear) {
+ if(linear->size >= size)
+ return linear;
+
+ if(xf86ResizeOffscreenLinear(linear, size))
+ return linear;
+
+ xf86FreeOffscreenLinear(linear);
+ }
+
+ pScreen = screenInfo.screens[pScrn->scrnIndex];
+
+ new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
+ NULL, NULL, NULL);
+
+ if(!new_linear) {
+ int max_size;
+
+ xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
+ PRIORITY_EXTREME);
+
+ if(max_size < size)
+ return NULL;
+
+ xf86PurgeUnlockedOffscreenAreas(pScreen);
+ new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
+ NULL, NULL, NULL);
+ }
+
+ return new_linear;
+}
+
+static void
+MGADisplayVideoOverlay(
+ ScrnInfoPtr pScrn,
+ int id,
+ int offset,
+ short width, short height,
+ int pitch,
+ int x1, int y1, int x2, int y2,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ int tmp, hzoom, intrep;
+
+ CHECK_DMA_QUIESCENT(pMga, pScrn);
+
+ /* got 48 scanlines to do it in */
+ tmp = INREG(MGAREG_VCOUNT) + 48;
+ /* FIXME always change it in vertical retrace use CrtcV ?*/
+ if(tmp > pScrn->currentMode->CrtcVTotal)
+ tmp -= 49; /* too bad */
+ else
+ tmp = pScrn->currentMode->CrtcVTotal -1;
+
+ tmp = pScrn->currentMode->VDisplay +1;
+ /* enable accelerated 2x horizontal zoom when pixelclock >135MHz */
+ hzoom = (pScrn->currentMode->Clock > 135000) ? 1 : 0;
+
+ switch(id) {
+ case FOURCC_UYVY:
+ OUTREG(MGAREG_BESGLOBCTL, 0x000000c0 | (3 * hzoom) | (tmp << 16));
+ break;
+ case FOURCC_YUY2:
+ default:
+ OUTREG(MGAREG_BESGLOBCTL, 0x00000080 | (3 * hzoom) | (tmp << 16));
+ break;
+ }
+
+ OUTREG(MGAREG_BESA1ORG, offset);
+
+ if(y1 & 0x00010000)
+ OUTREG(MGAREG_BESCTL, 0x00040c41);
+ else
+ OUTREG(MGAREG_BESCTL, 0x00040c01);
+
+ OUTREG(MGAREG_BESHCOORD, (dstBox->x1 << 16) | (dstBox->x2 - 1));
+ OUTREG(MGAREG_BESVCOORD, (dstBox->y1 << 16) | (dstBox->y2 - 1));
+
+ OUTREG(MGAREG_BESHSRCST, x1 & 0x03fffffc);
+ OUTREG(MGAREG_BESHSRCEND, (x2 - 0x00010000) & 0x03fffffc);
+ OUTREG(MGAREG_BESHSRCLST, (width - 1) << 16);
+
+ OUTREG(MGAREG_BESPITCH, pitch >> 1);
+
+ OUTREG(MGAREG_BESV1WGHT, y1 & 0x0000fffc);
+ OUTREG(MGAREG_BESV1SRCLST, height - 1 - (y1 >> 16));
+
+ intrep = ((drw_h == src_h) || (drw_h < 2)) ? 0 : 1;
+ tmp = ((src_h - intrep) << 16)/(drw_h - intrep);
+ if(tmp >= (32 << 16))
+ tmp = (32 << 16) - 1;
+ OUTREG(MGAREG_BESVISCAL, tmp & 0x001ffffc);
+
+ intrep = ((drw_w == src_w) || (drw_w < 2)) ? 0 : 1;
+ tmp = (((src_w - intrep) << 16)/(drw_w - intrep)) << hzoom;
+ if(tmp >= (32 << 16))
+ tmp = (32 << 16) - 1;
+ OUTREG(MGAREG_BESHISCAL, tmp & 0x001ffffc);
+
+}
+
+static void
+MGADisplayVideoTexture(
+ ScrnInfoPtr pScrn,
+ int id, int offset,
+ int nbox, BoxPtr pbox,
+ int width, int height, int pitch,
+ short src_x, short src_y,
+ short src_w, short src_h,
+ short drw_x, short drw_y,
+ short drw_w, short drw_h
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ int log2w = 0, log2h = 0, i, incx, incy, padw, padh;
+
+ pitch >>= 1;
+
+ i = 12;
+ while(--i) {
+ if(width & (1 << i)) {
+ log2w = i;
+ if(width & ((1 << i) - 1))
+ log2w++;
+ break;
+ }
+ }
+
+ i = 12;
+ while(--i) {
+ if(height & (1 << i)) {
+ log2h = i;
+ if(height & ((1 << i) - 1))
+ log2h++;
+ break;
+ }
+ }
+
+ padw = 1 << log2w;
+ padh = 1 << log2h;
+ incx = (src_w << 20)/(drw_w * padw);
+ incy = (src_h << 20)/(drw_h * padh);
+
+ CHECK_DMA_QUIESCENT(pMga, pScrn);
+
+ if(pMga->Overlay8Plus24) {
+ i = 0x00ffffff;
+ WAITFIFO(1);
+ SET_PLANEMASK(i);
+ }
+
+ WAITFIFO(15);
+ OUTREG(MGAREG_TMR0, incx); /* sx inc */
+ OUTREG(MGAREG_TMR1, 0); /* sy inc */
+ OUTREG(MGAREG_TMR2, 0); /* tx inc */
+ OUTREG(MGAREG_TMR3, incy); /* ty inc */
+ OUTREG(MGAREG_TMR4, 0x00000000);
+ OUTREG(MGAREG_TMR5, 0x00000000);
+ OUTREG(MGAREG_TMR8, 0x00010000);
+ OUTREG(MGAREG_TEXORG, offset);
+ OUTREG(MGAREG_TEXWIDTH, log2w | (((8 - log2w) & 63) << 9) |
+ ((width - 1) << 18));
+ OUTREG(MGAREG_TEXHEIGHT, log2h | (((8 - log2h) & 63) << 9) |
+ ((height - 1) << 18));
+ if(id == FOURCC_UYVY)
+ OUTREG(MGAREG_TEXCTL, 0x1A00010b | ((pitch & 0x07FF) << 9));
+ else
+ OUTREG(MGAREG_TEXCTL, 0x1A00010a | ((pitch & 0x07FF) << 9));
+ OUTREG(MGAREG_TEXCTL2, 0x00000014);
+ OUTREG(MGAREG_DWGCTL, 0x000c7076);
+ OUTREG(MGAREG_TEXFILTER, 0x01e00020);
+ OUTREG(MGAREG_ALPHACTRL, 0x00000001);
+
+ padw = (src_x << 20)/padw;
+ padh = (src_y << 20)/padh;
+
+ while(nbox--) {
+ WAITFIFO(4);
+ OUTREG(MGAREG_TMR6, (incx * (pbox->x1 - drw_x)) + padw);
+ OUTREG(MGAREG_TMR7, (incy * (pbox->y1 - drw_y)) + padh);
+ OUTREG(MGAREG_FXBNDRY, (pbox->x2 << 16) | (pbox->x1 & 0xffff));
+ OUTREG(MGAREG_YDSTLEN + MGAREG_EXEC,
+ (pbox->y1 << 16) | (pbox->y2 - pbox->y1));
+ pbox++;
+ }
+
+ pMga->AccelInfoRec->NeedToSync = TRUE;
+}
+
+static int
+MGAPutImage(
+ 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
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+ INT32 x1, x2, y1, y2;
+ unsigned char *dst_start;
+ int pitch, new_size, offset, offset2 = 0, offset3 = 0;
+ int srcPitch, srcPitch2 = 0, dstPitch;
+ int top, left, npixels, nlines, bpp;
+ BoxRec dstBox;
+ CARD32 tmp;
+
+ /* Clip */
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dstBox.x1 = drw_x;
+ dstBox.x2 = drw_x + drw_w;
+ dstBox.y1 = drw_y;
+ dstBox.y2 = drw_y + drw_h;
+
+ if(!MGAClipVideo(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
+ return Success;
+
+ if(!pMga->TexturedVideo) {
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+ }
+
+ bpp = pScrn->bitsPerPixel >> 3;
+ pitch = bpp * pScrn->displayWidth;
+
+ dstPitch = ((width << 1) + 15) & ~15;
+ new_size = ((dstPitch * height) + bpp - 1) / bpp;
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ srcPitch = (width + 3) & ~3;
+ offset2 = srcPitch * height;
+ srcPitch2 = ((width >> 1) + 3) & ~3;
+ offset3 = (srcPitch2 * (height >> 1)) + offset2;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ srcPitch = (width << 1);
+ break;
+ }
+
+ if(!(pPriv->linear = MGAAllocateMemory(pScrn, pPriv->linear,
+ pPriv->doubleBuffer ? (new_size << 1) : new_size)))
+ {
+ return BadAlloc;
+ }
+ pPriv->currentBuffer ^= 1;
+
+ /* copy data */
+ top = y1 >> 16;
+ left = (x1 >> 16) & ~1;
+ npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
+ left <<= 1;
+
+ offset = pPriv->linear->offset * bpp;
+ if(pPriv->doubleBuffer)
+ offset += pPriv->currentBuffer * new_size * bpp;
+ dst_start = pMga->FbStart + offset + left + (top * dstPitch);
+
+ if(pMga->TexturedVideo && pMga->AccelInfoRec->NeedToSync &&
+ ((long)data != pPriv->lastPort))
+ {
+ MGAStormSync(pScrn);
+ }
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ top &= ~1;
+ tmp = ((top >> 1) * srcPitch2) + (left >> 2);
+ offset2 += tmp;
+ offset3 += tmp;
+ if(id == FOURCC_I420) {
+ tmp = offset2;
+ offset2 = offset3;
+ offset3 = tmp;
+ }
+ nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
+ MGACopyMungedData(buf + (top * srcPitch) + (left >> 1),
+ buf + offset2, buf + offset3, dst_start,
+ srcPitch, srcPitch2, dstPitch, nlines, npixels);
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ buf += (top * srcPitch) + left;
+ nlines = ((y2 + 0xffff) >> 16) - top;
+ MGACopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
+ break;
+ }
+
+ if(pMga->TexturedVideo) {
+ pPriv->lastPort = (long)data;
+ MGADisplayVideoTexture(pScrn, id, offset,
+ REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes),
+ width, height, dstPitch, src_x, src_y, src_w, src_h,
+ drw_x, drw_y, drw_w, drw_h);
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ } else {
+ /* update cliplist */
+ if(!RegionsEqual(&pPriv->clip, clipBoxes)) {
+ REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+ /* draw these */
+ XAAFillSolidRects(pScrn, pPriv->colorKey, GXcopy, ~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+ }
+
+ offset += top * dstPitch;
+ MGADisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
+ x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+ }
+ pMga->VideoTimerCallback = MGAVideoTimerCallback;
+
+ return Success;
+}
+
+
+static int
+MGAQueryImageAttributes(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets
+){
+ MGAPtr pMga = MGAPTR(pScrn);
+ int size, tmp;
+
+ if(pMga->TexturedVideo) {
+ if(*w > 2046) *w = 2046;
+ if(*h > 2046) *h = 2046;
+ } else {
+ 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 void
+MGAVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
+{
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr pPriv = pMga->portPrivate;
+
+ if(pPriv->videoStatus & TIMER_MASK) {
+ if(pPriv->videoStatus & OFF_TIMER) {
+ if(pPriv->offTime < time) {
+ OUTREG(MGAREG_BESCTL, 0);
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = time + FREE_DELAY;
+ }
+ } else { /* FREE_TIMER */
+ if(pPriv->freeTime < time) {
+ if(pPriv->linear) {
+ xf86FreeOffscreenLinear(pPriv->linear);
+ pPriv->linear = NULL;
+ }
+ pPriv->videoStatus = 0;
+ pMga->VideoTimerCallback = NULL;
+ }
+ }
+ } else /* shouldn't get here */
+ pMga->VideoTimerCallback = NULL;
+}
+
+
+/****************** Offscreen stuff ***************/
+
+typedef struct {
+ FBLinearPtr linear;
+ Bool isOn;
+} OffscreenPrivRec, * OffscreenPrivPtr;
+
+static int
+MGAAllocateSurface(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short w,
+ unsigned short h,
+ XF86SurfacePtr surface
+){
+ FBLinearPtr linear;
+ int pitch, fbpitch, size, bpp;
+ OffscreenPrivPtr pPriv;
+
+ if((w > 1024) || (h > 1024))
+ return BadAlloc;
+
+ w = (w + 1) & ~1;
+ pitch = ((w << 1) + 15) & ~15;
+ bpp = pScrn->bitsPerPixel >> 3;
+ fbpitch = bpp * pScrn->displayWidth;
+ size = ((pitch * h) + bpp - 1) / bpp;
+
+ if(!(linear = MGAAllocateMemory(pScrn, NULL, size)))
+ return BadAlloc;
+
+ surface->width = w;
+ surface->height = h;
+
+ if(!(surface->pitches = xalloc(sizeof(int)))) {
+ xf86FreeOffscreenLinear(linear);
+ return BadAlloc;
+ }
+ if(!(surface->offsets = xalloc(sizeof(int)))) {
+ xfree(surface->pitches);
+ xf86FreeOffscreenLinear(linear);
+ return BadAlloc;
+ }
+ if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ xf86FreeOffscreenLinear(linear);
+ return BadAlloc;
+ }
+
+ pPriv->linear = linear;
+ pPriv->isOn = FALSE;
+
+ surface->pScrn = pScrn;
+ surface->id = id;
+ surface->pitches[0] = pitch;
+ surface->offsets[0] = linear->offset * bpp;
+ surface->devPrivate.ptr = (pointer)pPriv;
+
+ return Success;
+}
+
+static int
+MGAStopSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+
+ if(pPriv->isOn) {
+ MGAPtr pMga = MGAPTR(surface->pScrn);
+ OUTREG(MGAREG_BESCTL, 0);
+ pPriv->isOn = FALSE;
+ }
+
+ return Success;
+}
+
+
+static int
+MGAFreeSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+
+ if(pPriv->isOn)
+ MGAStopSurface(surface);
+ xf86FreeOffscreenLinear(pPriv->linear);
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ xfree(surface->devPrivate.ptr);
+
+ return Success;
+}
+
+static int
+MGAGetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value
+){
+ return MGAGetPortAttributeOverlay(pScrn, attribute, value, 0);
+}
+
+static int
+MGASetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value
+){
+ return MGASetPortAttributeOverlay(pScrn, attribute, value, 0);
+}
+
+
+static int
+MGADisplaySurface(
+ XF86SurfacePtr surface,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ RegionPtr clipBoxes
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+ ScrnInfoPtr pScrn = surface->pScrn;
+ MGAPtr pMga = MGAPTR(pScrn);
+ MGAPortPrivPtr portPriv = pMga->portPrivate;
+ INT32 x1, y1, x2, y2;
+ BoxRec dstBox;
+
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dstBox.x1 = drw_x;
+ dstBox.x2 = drw_x + drw_w;
+ dstBox.y1 = drw_y;
+ dstBox.y2 = drw_y + drw_h;
+
+ if(!MGAClipVideo(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
+ surface->width, surface->height))
+ {
+ return Success;
+ }
+
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+
+ MGAResetVideoOverlay(pScrn);
+
+ MGADisplayVideoOverlay(pScrn, surface->id, surface->offsets[0],
+ surface->width, surface->height, surface->pitches[0],
+ x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ XAAFillSolidRects(pScrn, portPriv->colorKey, GXcopy, ~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+
+ pPriv->isOn = TRUE;
+ /* we've prempted the XvImage stream so set its free timer */
+ if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
+ REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
+ UpdateCurrentTime();
+ portPriv->videoStatus = FREE_TIMER;
+ portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ pMga->VideoTimerCallback = MGAVideoTimerCallback;
+ }
+
+ return Success;
+}
+
+
+static void
+MGAInitOffscreenImages(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ MGAPtr pMga = MGAPTR(pScrn);
+ int num = (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550) ? 2 : 1;
+ XF86OffscreenImagePtr offscreenImages;
+
+ /* need to free this someplace */
+ if(!(offscreenImages = xalloc(num * sizeof(XF86OffscreenImageRec))))
+ return;
+
+ offscreenImages[0].image = &Images[0];
+ offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
+ VIDEO_CLIP_TO_VIEWPORT;
+ offscreenImages[0].alloc_surface = MGAAllocateSurface;
+ offscreenImages[0].free_surface = MGAFreeSurface;
+ offscreenImages[0].display = MGADisplaySurface;
+ offscreenImages[0].stop = MGAStopSurface;
+ offscreenImages[0].setAttribute = MGASetSurfaceAttribute;
+ offscreenImages[0].getAttribute = MGAGetSurfaceAttribute;
+ offscreenImages[0].max_width = 1024;
+ offscreenImages[0].max_height = 1024;
+ offscreenImages[0].num_attributes = (num == 1) ? 1 : 4;
+ offscreenImages[0].attributes = Attributes;
+
+ if(num == 2) {
+ offscreenImages[1].image = &Images[3];
+ offscreenImages[1].flags = VIDEO_OVERLAID_IMAGES |
+ VIDEO_CLIP_TO_VIEWPORT;
+ offscreenImages[1].alloc_surface = MGAAllocateSurface;
+ offscreenImages[1].free_surface = MGAFreeSurface;
+ offscreenImages[1].display = MGADisplaySurface;
+ offscreenImages[1].stop = MGAStopSurface;
+ offscreenImages[1].setAttribute = MGASetSurfaceAttribute;
+ offscreenImages[1].getAttribute = MGAGetSurfaceAttribute;
+ offscreenImages[1].max_width = 1024;
+ offscreenImages[1].max_height = 1024;
+ offscreenImages[1].num_attributes = 4;
+ offscreenImages[1].attributes = Attributes;
+ }
+
+ xf86XVRegisterOffscreenImages(pScreen, offscreenImages, num);
+}
+
+#endif /* !XvExtension */