/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/chips/ct_video.c,v 1.15 2003/07/17 08:19:35 eich 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 "ct_driver.h" #include "Xv.h" #include "xaa.h" #include "xaalocal.h" #include "dixstruct.h" #include "fourcc.h" #define OFF_DELAY 200 /* milliseconds */ #define FREE_DELAY 60000 #define OFF_TIMER 0x01 #define FREE_TIMER 0x02 #define CLIENT_VIDEO_ON 0x04 #define TIMER_MASK (OFF_TIMER | FREE_TIMER) static XF86VideoAdaptorPtr CHIPSSetupImageVideo(ScreenPtr); static void CHIPSInitOffscreenImages(ScreenPtr); static void CHIPSStopVideo(ScrnInfoPtr, pointer, Bool); static int CHIPSSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); static int CHIPSGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); static void CHIPSQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer); static int CHIPSPutImage( ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer); static int CHIPSQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *, int *, int *); static void CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time); #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) static Atom xvColorKey; void CHIPSInitVideo(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; XF86VideoAdaptorPtr newAdaptor = NULL; CHIPSPtr cPtr = CHIPSPTR(pScrn); int num_adaptors; if (!(cPtr->Flags & ChipsOverlay8plus16) && (cPtr->Flags & ChipsVideoSupport)) { newAdaptor = CHIPSSetupImageVideo(pScreen); CHIPSInitOffscreenImages(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[1] = { { 0, "XV_IMAGE", 1024, 1024, {1, 1} } }; #define NUM_FORMATS 4 static XF86VideoFormatRec Formats[NUM_FORMATS] = { {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor} }; #define NUM_ATTRIBUTES 1 static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"} }; #define NUM_IMAGES 4 static XF86ImageRec Images[NUM_IMAGES] = { { 0x35315652, XvRGB, LSBFirst, {'R','V','1','5', 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 16, XvPacked, 1, 15, 0x7C00, 0x03E0, 0x001F, 0, 0, 0, 0, 0, 0, 0, 0, 0, {'R','V','B',0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, XvTopToBottom }, { 0x36315652, XvRGB, LSBFirst, {'R','V','1','6', 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 16, XvPacked, 1, 16, 0xF800, 0x07E0, 0x001F, 0, 0, 0, 0, 0, 0, 0, 0, 0, {'R','V','B',0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, XvTopToBottom }, XVIMAGE_YV12, XVIMAGE_YUY2 }; typedef struct { FBLinearPtr linear; RegionRec clip; CARD32 colorKey; CARD32 videoStatus; Time offTime; Time freeTime; Bool doubleBuffer; Bool manualDoubleBuffer; int currentBuffer; } CHIPSPortPrivRec, *CHIPSPortPrivPtr; #define GET_PORT_PRIVATE(pScrn) \ (CHIPSPortPrivPtr)((CHIPSPTR(pScrn))->adaptor->pPortPrivates[0].ptr) void CHIPSResetVideo(ScrnInfoPtr pScrn) { CHIPSPtr cPtr = CHIPSPTR(pScrn); CHIPSPortPrivPtr pPriv = cPtr->adaptor->pPortPrivates[0].ptr; unsigned char mr3c; int red, green, blue; if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); mr3c = cPtr->readMR(cPtr, 0x3C); cPtr->writeMR(cPtr, 0x3C, (mr3c | 0x6)); switch (pScrn->depth) { case 8: cPtr->writeMR(cPtr, 0x3D, 0x00); cPtr->writeMR(cPtr, 0x3E, 0x00); cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF)); cPtr->writeMR(cPtr, 0x40, 0xFF); cPtr->writeMR(cPtr, 0x41, 0xFF); cPtr->writeMR(cPtr, 0x42, 0x00); break; default: red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red; green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green; blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue; switch (pScrn->depth) { case 15: cPtr->writeMR(cPtr, 0x3D, (red << 3)); cPtr->writeMR(cPtr, 0x3E, (green << 3)); cPtr->writeMR(cPtr, 0x3F, (blue << 3)); cPtr->writeMR(cPtr, 0x40, 0x07); cPtr->writeMR(cPtr, 0x41, 0x07); cPtr->writeMR(cPtr, 0x42, 0x07); break; case 16: cPtr->writeMR(cPtr, 0x3D, (red << 3)); cPtr->writeMR(cPtr, 0x3E, (green << 2)); cPtr->writeMR(cPtr, 0x3F, (blue << 3)); cPtr->writeMR(cPtr, 0x40, 0x07); cPtr->writeMR(cPtr, 0x41, 0x03); cPtr->writeMR(cPtr, 0x42, 0x07); break; case 24: cPtr->writeMR(cPtr, 0x3D, red); cPtr->writeMR(cPtr, 0x3E, green); cPtr->writeMR(cPtr, 0x3F, blue); cPtr->writeMR(cPtr, 0x40, 0x00); cPtr->writeMR(cPtr, 0x41, 0x00); cPtr->writeMR(cPtr, 0x42, 0x00); break; } } } static XF86VideoAdaptorPtr CHIPSSetupImageVideo(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; CHIPSPtr cPtr = CHIPSPTR(pScrn); XF86VideoAdaptorPtr adapt; CHIPSPortPrivPtr pPriv; if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + sizeof(CHIPSPortPrivRec) + sizeof(DevUnion)))) return NULL; adapt->type = XvWindowMask | XvInputMask | XvImageMask; adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; adapt->name = "Chips and Technologies Backend Scaler"; adapt->nEncodings = 1; adapt->pEncodings = DummyEncoding; adapt->nFormats = NUM_FORMATS; adapt->pFormats = Formats; adapt->nPorts = 1; adapt->pPortPrivates = (DevUnion*)(&adapt[1]); pPriv = (CHIPSPortPrivPtr)(&adapt->pPortPrivates[1]); adapt->pPortPrivates[0].ptr = (pointer)(pPriv); adapt->pAttributes = Attributes; adapt->nImages = NUM_IMAGES; adapt->nAttributes = NUM_ATTRIBUTES; adapt->pImages = Images; adapt->PutVideo = NULL; adapt->PutStill = NULL; adapt->GetVideo = NULL; adapt->GetStill = NULL; adapt->StopVideo = CHIPSStopVideo; adapt->SetPortAttribute = CHIPSSetPortAttribute; adapt->GetPortAttribute = CHIPSGetPortAttribute; adapt->QueryBestSize = CHIPSQueryBestSize; adapt->PutImage = CHIPSPutImage; adapt->QueryImageAttributes = CHIPSQueryImageAttributes; pPriv->colorKey = cPtr->videoKey; pPriv->videoStatus = 0; pPriv->doubleBuffer = TRUE; pPriv->manualDoubleBuffer = FALSE; pPriv->currentBuffer = 0; /* gotta uninit this someplace */ REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); cPtr->adaptor = adapt; xvColorKey = MAKE_ATOM("XV_COLORKEY"); CHIPSResetVideo(pScrn); return adapt; } static void CHIPSStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shadow) { CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data; CHIPSPtr cPtr = CHIPSPTR(pScrn); unsigned char mr3c, tmp; REGION_EMPTY(pScrn->pScreen, &pPriv->clip); if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); if(shadow) { if(pPriv->videoStatus & CLIENT_VIDEO_ON) { mr3c = cPtr->readMR(cPtr, 0x3C); cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE)); tmp = cPtr->readXR(cPtr, 0xD0); cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf)); } 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; cPtr->VideoTimerCallback = CHIPSVideoTimerCallback; } } } static int CHIPSSetPortAttribute( ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data ){ CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data; CHIPSPtr cPtr = CHIPSPTR(pScrn); if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); if(attribute == xvColorKey) { int red, green, blue; pPriv->colorKey = value; switch (pScrn->depth) { case 8: cPtr->writeMR(cPtr, 0x3D, 0x00); cPtr->writeMR(cPtr, 0x3E, 0x00); cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF)); break; default: red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red; green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green; blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue; switch (pScrn->depth) { case 15: cPtr->writeMR(cPtr, 0x3D, (red << 3)); cPtr->writeMR(cPtr, 0x3E, (green << 3)); cPtr->writeMR(cPtr, 0x3F, (blue << 3)); break; case 16: cPtr->writeMR(cPtr, 0x3D, (red << 3)); cPtr->writeMR(cPtr, 0x3E, (green << 2)); cPtr->writeMR(cPtr, 0x3F, (blue << 3)); break; case 24: cPtr->writeMR(cPtr, 0x3D, red); cPtr->writeMR(cPtr, 0x3E, green); cPtr->writeMR(cPtr, 0x3F, blue); break; } } REGION_EMPTY(pScrn->pScreen, &pPriv->clip); } else return BadMatch; return Success; } static int CHIPSGetPortAttribute( ScrnInfoPtr pScrn, Atom attribute, INT32 *value, pointer data ){ CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data; if(attribute == xvColorKey) { *value = pPriv->colorKey; } else return BadMatch; return Success; } static void CHIPSQueryBestSize( 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; if(*p_w > 16384) *p_w = 16384; } static void CHIPSCopyData( 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 CHIPSCopyMungedData( unsigned char *src1, unsigned char *src2, unsigned char *src3, unsigned char *dst1, int srcPitch, int srcPitch2, int dstPitch, int h, int w ){ CARD32 *dst = (CARD32*)dst1; int i, j; dstPitch >>= 2; w >>= 1; for(j = 0; j < h; j++) { for(i = 0; i < w; i++) { dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) | (src3[i] << 8) | (src2[i] << 24); } dst += dstPitch; src1 += srcPitch; if(j & 1) { src2 += srcPitch2; src3 += srcPitch2; } } } static FBLinearPtr CHIPSAllocateMemory( 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, 8, NULL, NULL, NULL); if(!new_linear) { int max_size; xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8, PRIORITY_EXTREME); if(max_size < size) return NULL; xf86PurgeUnlockedOffscreenAreas(pScreen); new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8, NULL, NULL, NULL); } return new_linear; } static int CHIPSSetCurrentPlaybackBuffer(CHIPSPtr cPtr, int n) { CARD8 mr20; mr20 = cPtr->readMR(cPtr, 0x20); mr20 &= ~0x1B; if (!n) mr20 |= 0x10; cPtr->writeMR(cPtr, 0x22, mr20); return n; } static int CHIPSWaitGetNextFrame(CHIPSPtr cPtr) { volatile CARD8 mr20; volatile CARD8 mr21; mr20 = cPtr->readMR(cPtr, 0x20); while (1) { mr21 = cPtr->readMR(cPtr, 0x21); if (!(mr20 & (1 << 5)) || !(mr21 & 1)) break; } mr20 &= ~0x4; mr20 = cPtr->readMR(cPtr, 0x20); return (mr21 & 2)? 0 : 1; } static void CHIPSDisplayVideo( 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, Bool triggerBufSwitch ){ CHIPSPtr cPtr = CHIPSPTR(pScrn); CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); DisplayModePtr mode = pScrn->currentMode; unsigned char tmp, m1f, m1e; int buffer = pPriv->currentBuffer; if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); tmp = cPtr->readXR(cPtr, 0xD0); cPtr->writeXR(cPtr, 0xD0, (tmp | 0x10)); m1e = cPtr->readMR(cPtr, 0x1E); m1e &= 0xE0; /* Set Zoom and Direction */ if ((!(cPtr->PanelType & ChipsLCD)) && (mode->Flags & V_INTERLACE)) m1e |= 0x10; m1f = cPtr->readMR(cPtr, 0x1F); m1f = (m1f & 0x14); /* Mask reserved bits, unset interpolation */ switch(id) { case 0x35315652: /* RGB15 */ m1f |= 0x09; break; case 0x36315652: /* RGB16 */ m1f |= 0x08; break; case FOURCC_YV12: /* YV12 */ /* m1f |= 0x03 */ m1f |= 0x00; break; case FOURCC_YUY2: /* YUY2 */ default: m1f |= 0x00; /* Do nothing here */ break; } offset += (x1 >> 15) & ~0x01; /* Setup Pointer 1 */ if (!buffer || pPriv->manualDoubleBuffer || !pPriv->doubleBuffer) { cPtr->writeMR(cPtr, 0x22, (offset & 0xF8)); cPtr->writeMR(cPtr, 0x23, ((offset >> 8) & 0xFF)); cPtr->writeMR(cPtr, 0x24, ((offset >> 16) & 0xFF)); } /* Setup Pointer 2 */ if ((buffer && !pPriv->manualDoubleBuffer) || !pPriv->doubleBuffer) { cPtr->writeMR(cPtr, 0x25, (offset & 0xF8)); cPtr->writeMR(cPtr, 0x26, ((offset >> 8) & 0xFF)); cPtr->writeMR(cPtr, 0x27, ((offset >> 16) & 0xFF)); } tmp = cPtr->readMR(cPtr, 0x04); if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch) tmp |= 0x18; cPtr->writeMR(cPtr, 0x04, tmp); tmp = cPtr->readMR(cPtr, 0x20); tmp &= 0xC3; if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch) tmp |= ((1 << 2 | 1 << 5) | ((buffer) ? (1 << 4) : 0)); cPtr->writeMR(cPtr, 0x20, tmp); cPtr->writeMR(cPtr, 0x28, ((width >> 2) - 1)); /* Width */ cPtr->writeMR(cPtr, 0x34, ((width >> 2) - 1)); /* Left Edge of Overlay */ cPtr->writeMR(cPtr, 0x2A, ((cPtr->OverlaySkewX + dstBox->x1) & 0xFF)); tmp = cPtr->readMR(cPtr, 0x2B); tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x1) >> 8) & 0x07); cPtr->writeMR(cPtr, 0x2B, tmp); /* Right Edge of Overlay */ cPtr->writeMR(cPtr, 0x2C, ((cPtr->OverlaySkewX + dstBox->x2 -1) & 0xFF)); tmp = cPtr->readMR(cPtr, 0x2D); tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x2 - 1) >> 8) & 0x07); cPtr->writeMR(cPtr, 0x2D, tmp); /* Top Edge of Overlay */ cPtr->writeMR(cPtr, 0x2E, ((cPtr->OverlaySkewY + dstBox->y1) & 0xFF)); tmp = cPtr->readMR(cPtr, 0x2F); tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewY + dstBox->y1) >> 8) & 0x07); cPtr->writeMR(cPtr, 0x2F, tmp); /* Bottom Edge of Overlay*/ cPtr->writeMR(cPtr, 0x30, ((cPtr->OverlaySkewY + dstBox->y2 - 1) & 0xFF)); tmp = cPtr->readMR(cPtr, 0x31); tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewY + dstBox->y2 - 1) >> 8) & 0x07); cPtr->writeMR(cPtr, 0x31, tmp); /* Horizontal Zoom */ if (drw_w > src_w) { m1f = m1f | 0x20; /* set H-interpolation */ m1e = m1e | 0x04; tmp = cPtr->VideoZoomMax * src_w / drw_w; cPtr->writeMR(cPtr, 0x32, tmp); } /* Vertical Zoom */ if (drw_h > src_h) { m1f = m1f | 0x80; /* set V-interpolation */ m1e = m1e | 0x08; tmp = cPtr->VideoZoomMax * src_h / drw_h ; cPtr->writeMR(cPtr, 0x33, tmp); } cPtr->writeMR(cPtr, 0x1F, m1f); cPtr->writeMR(cPtr, 0x1E, m1e); tmp = cPtr->readMR(cPtr, 0x3C); cPtr->writeMR(cPtr, 0x3C, (tmp | 0x7)); if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); } static int CHIPSPutImage( 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 ){ CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data; CHIPSPtr cPtr = CHIPSPTR(pScrn); 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; if(drw_w > 16384) drw_w = 16384; /* Clip */ x1 = src_x; x2 = src_x + src_w; y1 = src_y; y2 = src_y + src_h; dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height)) return Success; dstBox.x1 -= pScrn->frameX0 & cPtr->viewportMask; dstBox.x2 -= pScrn->frameX0 & cPtr->viewportMask; 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; if (pPriv->doubleBuffer) new_size <<= 1; switch(id) { case FOURCC_YV12: /* YV12 */ srcPitch = (width + 3) & ~3; offset2 = srcPitch * height; srcPitch2 = ((width >> 1) + 3) & ~3; offset3 = (srcPitch2 * (height >> 1)) + offset2; break; default: /* RGB15, RGB16, YUY2 */ srcPitch = (width << 1); break; } if(!(pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear, new_size))) { if (pPriv->doubleBuffer && (pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear, new_size >> 1))) { new_size >>= 1; pPriv->doubleBuffer = FALSE; } else return BadAlloc; } /* 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->manualDoubleBuffer) pPriv->currentBuffer = CHIPSWaitGetNextFrame(cPtr); if(pPriv->doubleBuffer && pPriv->currentBuffer) offset += (new_size * bpp) >> 1; dst_start = cPtr->FbBase + offset + left + (top * dstPitch); switch(id) { case FOURCC_YV12: /* YV12 */ top &= ~1; tmp = ((top >> 1) * srcPitch2) + (left >> 2); offset2 += tmp; offset3 += tmp; nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; CHIPSCopyMungedData(buf + (top * srcPitch) + (left >> 1), buf + offset2, buf + offset3, dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels); break; default: /* RGB15, RGB16, YUY2 */ buf += (top * srcPitch) + left; nlines = ((y2 + 0xffff) >> 16) - top; CHIPSCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels); break; } /* update cliplist */ if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); } offset += top * dstPitch; CHIPSDisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, TRUE); pPriv->videoStatus = CLIENT_VIDEO_ON; if (pPriv->manualDoubleBuffer) pPriv->currentBuffer ^= 1; return Success; } static int CHIPSQueryImageAttributes( ScrnInfoPtr pScrn, int id, unsigned short *w, unsigned short *h, int *pitches, int *offsets ){ int size, tmp; if(*w > 1024) *w = 1024; if(*h > 1024) *h = 1024; *w = (*w + 1) & ~1; if(offsets) offsets[0] = 0; switch(id) { case FOURCC_YV12: /* YV12 */ *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; default: /* RGB15, RGB16, YUY2 */ size = *w << 1; if(pitches) pitches[0] = size; size *= *h; break; } return size; } static void CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time) { CHIPSPtr cPtr = CHIPSPTR(pScrn); CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); unsigned char mr3c; if(pPriv->videoStatus & TIMER_MASK) { if(pPriv->videoStatus & OFF_TIMER) { if(pPriv->offTime < time) { if (cPtr->Flags & ChipsAccelSupport) CHIPSHiQVSync(pScrn); mr3c = cPtr->readMR(cPtr, 0x3C); cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE)); pPriv->videoStatus = FREE_TIMER; pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; } } else { /* FREE_TIMER */ if(pPriv->freeTime < time) { if(pPriv->linear) { xf86FreeOffscreenLinear(pPriv->linear); pPriv->linear = NULL; } pPriv->videoStatus = 0; cPtr->VideoTimerCallback = NULL; } } } else /* shouldn't get here */ cPtr->VideoTimerCallback = NULL; } /****************** Offscreen stuff ***************/ typedef struct { FBLinearPtr linear; Bool isOn; } OffscreenPrivRec, * OffscreenPrivPtr; static int CHIPSAllocateSurface( 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 = CHIPSAllocateMemory(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 CHIPSStopSurface( XF86SurfacePtr surface ){ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; if(pPriv->isOn) { CHIPSPtr cPtr = CHIPSPTR(surface->pScrn); unsigned char mr3c, tmp; tmp = cPtr->readXR(cPtr, 0xD0); cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf)); mr3c = cPtr->readMR(cPtr, 0x3C); cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE)); pPriv->isOn = FALSE; } return Success; } static int CHIPSFreeSurface( XF86SurfacePtr surface ){ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; if(pPriv->isOn) CHIPSStopSurface(surface); xf86FreeOffscreenLinear(pPriv->linear); xfree(surface->pitches); xfree(surface->offsets); xfree(surface->devPrivate.ptr); return Success; } static int CHIPSGetSurfaceAttribute( ScrnInfoPtr pScrn, Atom attribute, INT32 *value ){ return CHIPSGetPortAttribute(pScrn, attribute, value, (pointer)(GET_PORT_PRIVATE(pScrn))); } static int CHIPSSetSurfaceAttribute( ScrnInfoPtr pScrn, Atom attribute, INT32 value ){ return CHIPSSetPortAttribute(pScrn, attribute, value, (pointer)(GET_PORT_PRIVATE(pScrn))); } static int CHIPSDisplaySurface( 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; CHIPSPtr cPtr = CHIPSPTR(pScrn); CHIPSPortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn); 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(!xf86XVClipVideoHelper(&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; if (portPriv->doubleBuffer) portPriv->currentBuffer = CHIPSSetCurrentPlaybackBuffer(cPtr,0); else portPriv->currentBuffer = 0; CHIPSDisplayVideo(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, FALSE); xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes); pPriv->isOn = TRUE; if(portPriv->videoStatus & CLIENT_VIDEO_ON) { REGION_EMPTY(pScrn->pScreen, &portPriv->clip); UpdateCurrentTime(); portPriv->videoStatus = FREE_TIMER; portPriv->freeTime = currentTime.milliseconds + FREE_DELAY; cPtr->VideoTimerCallback = CHIPSVideoTimerCallback; } return Success; } static void CHIPSInitOffscreenImages(ScreenPtr pScreen) { XF86OffscreenImagePtr offscreenImages; /* need to free this someplace */ if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) return; offscreenImages[0].image = &Images[0]; offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; offscreenImages[0].alloc_surface = CHIPSAllocateSurface; offscreenImages[0].free_surface = CHIPSFreeSurface; offscreenImages[0].display = CHIPSDisplaySurface; offscreenImages[0].stop = CHIPSStopSurface; offscreenImages[0].setAttribute = CHIPSSetSurfaceAttribute; offscreenImages[0].getAttribute = CHIPSGetSurfaceAttribute; offscreenImages[0].max_width = 1024; offscreenImages[0].max_height = 1024; offscreenImages[0].num_attributes = NUM_ATTRIBUTES; offscreenImages[0].attributes = Attributes; xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); }