/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_video.c,v 1.11 2002/11/26 23:41:59 mvojkovi 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 "xf86xv.h" #include "Xv.h" #include "xaa.h" #include "xaalocal.h" #include "dixstruct.h" #include "fourcc.h" #include "nv_include.h" #define OFF_DELAY 450 /* milliseconds */ #define FREE_DELAY 10000 #define OFF_TIMER 0x01 #define FREE_TIMER 0x02 #define CLIENT_VIDEO_ON 0x04 #define TIMER_MASK (OFF_TIMER | FREE_TIMER) #ifndef XvExtension void NVInitVideo(ScreenPtr pScreen) {} #else typedef struct _NVPortPrivRec { short brightness; short contrast; short saturation; short hue; RegionRec clip; CARD32 colorKey; Bool autopaintColorKey; Bool doubleBuffer; CARD32 videoStatus; int currentBuffer; Time videoTime; Bool grabbedByV4L; Bool iturbt_709; FBLinearPtr linear; int pitch; int offset; } NVPortPrivRec, *NVPortPrivPtr; static XF86VideoAdaptorPtr NVSetupImageVideo(ScreenPtr); static void NVStopOverlay (ScrnInfoPtr); static void NVPutOverlayImage(ScrnInfoPtr pScrnInfo, int offset, int id, int dstPitch, BoxPtr dstBox, int x1, int y1, int x2, int y2, short width, short height, short src_w, short src_h, short dst_w, short dst_h, RegionPtr cliplist); static int NVSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); static int NVGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer); static void NVStopOverlayVideo(ScrnInfoPtr, pointer, Bool); static int NVPutImage( ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer); static void NVQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer); static int NVQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *, int *, int *); static void NVVideoTimerCallback(ScrnInfoPtr, Time); static void NVInitOffscreenImages (ScreenPtr pScreen); #define GET_OVERLAY_PRIVATE(pNv) \ (NVPortPrivPtr)((pNv)->overlayAdaptor->pPortPrivates[0].ptr) #define GET_BLIT_PRIVATE(pNv) \ (NVPortPrivPtr)((pNv)->blitAdaptor->pPortPrivates[0].ptr) #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) static Atom xvBrightness, xvContrast, xvColorKey, xvSaturation, xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer, xvITURBT709; /* client libraries expect an encoding */ static XF86VideoEncodingRec DummyEncoding = { 0, "XV_IMAGE", 2046, 2046, {1, 1} }; #define NUM_FORMATS_ALL 6 XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] = { {15, TrueColor}, {16, TrueColor}, {24, TrueColor}, {15, DirectColor}, {16, DirectColor}, {24, DirectColor} }; #define NUM_ATTRIBUTES 9 XF86AttributeRec NVAttributes[NUM_ATTRIBUTES] = { {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}, {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"}, {XvSettable , 0, 0, "XV_SET_DEFAULTS"}, {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"}, {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"}, {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"}, {XvSettable | XvGettable, 0, 360, "XV_HUE"}, {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"} }; #define NUM_IMAGES_ALL 4 static XF86ImageRec NVImages[NUM_IMAGES_ALL] = { XVIMAGE_YUY2, XVIMAGE_YV12, XVIMAGE_UYVY, XVIMAGE_I420 }; static void NVSetPortDefaults (ScrnInfoPtr pScrnInfo, NVPortPrivPtr pPriv) { NVPtr pNv = NVPTR(pScrnInfo); pPriv->brightness = 0; pPriv->contrast = 4096; pPriv->saturation = 4096; pPriv->hue = 0; pPriv->colorKey = pNv->videoKey; pPriv->autopaintColorKey = TRUE; pPriv->doubleBuffer = TRUE; pPriv->iturbt_709 = FALSE; } void NVResetVideo (ScrnInfoPtr pScrnInfo) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); RIVA_HW_INST *pRiva = &(pNv->riva); int satSine, satCosine; double angle; angle = (double)pPriv->hue * 3.1415927 / 180.0; satSine = pPriv->saturation * sin(angle); if (satSine < -1024) satSine = -1024; satCosine = pPriv->saturation * cos(angle); if (satCosine < -1024) satCosine = -1024; pRiva->PMC[0x00008910/4] = (pPriv->brightness << 16) | pPriv->contrast; pRiva->PMC[0x00008914/4] = (pPriv->brightness << 16) | pPriv->contrast; pRiva->PMC[0x00008918/4] = (satSine << 16) | (satCosine & 0xffff); pRiva->PMC[0x0000891C/4] = (satSine << 16) | (satCosine & 0xffff); pRiva->PMC[0x00008b00/4] = pPriv->colorKey; } static void NVStopOverlay (ScrnInfoPtr pScrnInfo) { NVPtr pNv = NVPTR(pScrnInfo); RIVA_HW_INST *pRiva = &(pNv->riva); pRiva->PMC[0x00008704/4] = 1; } static FBLinearPtr NVAllocateOverlayMemory( 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, 32, NULL, NULL, NULL); if(!new_linear) { int max_size; xf86QueryLargestOffscreenLinear(pScreen, &max_size, 32, PRIORITY_EXTREME); if(max_size < size) return NULL; xf86PurgeUnlockedOffscreenAreas(pScreen); new_linear = xf86AllocateOffscreenLinear(pScreen, size, 32, NULL, NULL, NULL); } return new_linear; } static void NVFreeOverlayMemory(ScrnInfoPtr pScrnInfo) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); if(pPriv->linear) { xf86FreeOffscreenLinear(pPriv->linear); pPriv->linear = NULL; } } void NVInitVideo (ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; XF86VideoAdaptorPtr overlayAdaptor = NULL; NVPtr pNv = NVPTR(pScrn); int num_adaptors; if((pScrn->bitsPerPixel != 8) && (pNv->riva.Architecture >= NV_ARCH_10)) { overlayAdaptor = NVSetupImageVideo(pScreen); if(overlayAdaptor) NVInitOffscreenImages(pScreen); } num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); if(overlayAdaptor) { int size = num_adaptors + 1; if((newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr*)))) { if(num_adaptors) memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); if(overlayAdaptor) { newAdaptors[num_adaptors] = overlayAdaptor; num_adaptors++; } adaptors = newAdaptors; } } if (num_adaptors) xf86XVScreenInit(pScreen, adaptors, num_adaptors); if (newAdaptors) xfree(newAdaptors); } static XF86VideoAdaptorPtr NVSetupImageVideo (ScreenPtr pScreen) { ScrnInfoPtr pScrnInfo = xf86Screens[pScreen->myNum]; NVPtr pNv = NVPTR(pScrnInfo); XF86VideoAdaptorPtr adapt; NVPortPrivPtr pPriv; if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + sizeof(NVPortPrivRec) + sizeof(DevUnion)))) { return NULL; } adapt->type = XvWindowMask | XvInputMask | XvImageMask; adapt->flags = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT; adapt->name = "NV Video Overlay"; adapt->nEncodings = 1; adapt->pEncodings = &DummyEncoding; adapt->nFormats = NUM_FORMATS_ALL; adapt->pFormats = NVFormats; adapt->nPorts = 1; adapt->pPortPrivates = (DevUnion*)(&adapt[1]); pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]); adapt->pPortPrivates[0].ptr = (pointer)(pPriv); adapt->pAttributes = NVAttributes; adapt->nAttributes = NUM_ATTRIBUTES; adapt->pImages = NVImages; adapt->nImages = NUM_IMAGES_ALL; adapt->PutVideo = NULL; adapt->PutStill = NULL; adapt->GetVideo = NULL; adapt->GetStill = NULL; adapt->StopVideo = NVStopOverlayVideo; adapt->SetPortAttribute = NVSetPortAttribute; adapt->GetPortAttribute = NVGetPortAttribute; adapt->QueryBestSize = NVQueryBestSize; adapt->PutImage = NVPutImage; adapt->QueryImageAttributes = NVQueryImageAttributes; pPriv->videoStatus = 0; pPriv->currentBuffer = 0; pPriv->grabbedByV4L = FALSE; NVSetPortDefaults (pScrnInfo, pPriv); /* gotta uninit this someplace */ REGION_INIT(pScreen, &pPriv->clip, NullBox, 0); pNv->overlayAdaptor = adapt; xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); xvContrast = MAKE_ATOM("XV_CONTRAST"); xvColorKey = MAKE_ATOM("XV_COLORKEY"); xvSaturation = MAKE_ATOM("XV_SATURATION"); xvHue = MAKE_ATOM("XV_HUE"); xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS"); xvITURBT709 = MAKE_ATOM("XV_ITURBT_709"); NVResetVideo(pScrnInfo); return adapt; } /* * RegionsEqual */ 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; } static void NVPutOverlayImage ( ScrnInfoPtr pScrnInfo, int offset, int id, int dstPitch, BoxPtr dstBox, int x1, int y1, int x2, int y2, short width, short height, short src_w, short src_h, short drw_w, short drw_h, RegionPtr clipBoxes ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); RIVA_HW_INST *pRiva = &(pNv->riva); int buffer = pPriv->currentBuffer; /* paint the color key */ if(pPriv->autopaintColorKey && (pPriv->grabbedByV4L || !RegionsEqual(&pPriv->clip, clipBoxes))) { /* we always paint V4L's color key */ if(!pPriv->grabbedByV4L) REGION_COPY(pScrnInfo->pScreen, &pPriv->clip, clipBoxes); xf86XVFillKeyHelper(pScrnInfo->pScreen, pPriv->colorKey, clipBoxes); } pRiva->PMC[(0x8900/4) + buffer] = offset; pRiva->PMC[(0x8928/4) + buffer] = (height << 16) | width; pRiva->PMC[(0x8930/4) + buffer] = ((y1 << 4) & 0xffff0000) | (x1 >> 12); pRiva->PMC[(0x8938/4) + buffer] = (src_w << 20) / drw_w; pRiva->PMC[(0x8940/4) + buffer] = (src_h << 20) / drw_h; pRiva->PMC[(0x8948/4) + buffer] = (dstBox->y1 << 16) | dstBox->x1; pRiva->PMC[(0x8950/4) + buffer] = ((dstBox->y2 - dstBox->y1) << 16) | (dstBox->x2 - dstBox->x1); dstPitch |= 1 << 20; /* use color key */ if(id != FOURCC_UYVY) dstPitch |= 1 << 16; if(pPriv->iturbt_709) dstPitch |= 1 << 24; pRiva->PMC[(0x8958/4) + buffer] = dstPitch; pRiva->PMC[0x00008704/4] = 0; pRiva->PMC[0x8700/4] = 1 << (buffer << 2); pPriv->videoStatus = CLIENT_VIDEO_ON; } /* * StopVideo */ static void NVStopOverlayVideo ( ScrnInfoPtr pScrnInfo, pointer data, Bool Exit ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = (NVPortPrivPtr)data; if(pPriv->grabbedByV4L) return; REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip); if(Exit) { if(pPriv->videoStatus & CLIENT_VIDEO_ON) NVStopOverlay(pScrnInfo); NVFreeOverlayMemory(pScrnInfo); pPriv->videoStatus = 0; pNv->VideoTimerCallback = NULL; } else { if(pPriv->videoStatus & CLIENT_VIDEO_ON) { pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON; pPriv->videoTime = currentTime.milliseconds + OFF_DELAY; pNv->VideoTimerCallback = NVVideoTimerCallback; } } } static int NVSetPortAttribute ( ScrnInfoPtr pScrnInfo, Atom attribute, INT32 value, pointer data ) { NVPortPrivPtr pPriv = (NVPortPrivPtr)data; if (attribute == xvBrightness) { if ((value < -512) || (value > 512)) return BadValue; pPriv->brightness = value; } else if (attribute == xvDoubleBuffer) { if ((value < 0) || (value > 1)) return BadValue; pPriv->doubleBuffer = value; } else if (attribute == xvContrast) { if ((value < 0) || (value > 8191)) return BadValue; pPriv->contrast = value; } else if (attribute == xvHue) { value %= 360; if (value < 0) value += 360; pPriv->hue = value; } else if (attribute == xvSaturation) { if ((value < 0) || (value > 8191)) return BadValue; pPriv->saturation = value; } else if (attribute == xvColorKey) { pPriv->colorKey = value; REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip); } else if (attribute == xvAutopaintColorKey) { if ((value < 0) || (value > 1)) return BadValue; pPriv->autopaintColorKey = value; } else if (attribute == xvITURBT709) { if ((value < 0) || (value > 1)) return BadValue; pPriv->iturbt_709 = value; } else if (attribute == xvSetDefaults) { NVSetPortDefaults(pScrnInfo, pPriv); } else return BadMatch; NVResetVideo(pScrnInfo); return Success; } static int NVGetPortAttribute ( ScrnInfoPtr pScrnInfo, Atom attribute, INT32 *value, pointer data ) { NVPortPrivPtr pPriv = (NVPortPrivPtr)data; if (attribute == xvBrightness) *value = pPriv->brightness; else if (attribute == xvDoubleBuffer) *value = (pPriv->doubleBuffer) ? 1 : 0; else if (attribute == xvContrast) *value = pPriv->contrast; else if (attribute == xvSaturation) *value = pPriv->saturation; else if (attribute == xvHue) *value = pPriv->hue; else if (attribute == xvColorKey) *value = pPriv->colorKey; else if (attribute == xvAutopaintColorKey) *value = (pPriv->autopaintColorKey) ? 1 : 0; else if (attribute == xvITURBT709) *value = (pPriv->iturbt_709) ? 1 : 0; else return BadMatch; return Success; } /* * QueryBestSize */ static void NVQueryBestSize ( ScrnInfoPtr pScrnInfo, Bool motion, short vid_w, short vid_h, short drw_w, short drw_h, unsigned int *p_w, unsigned int *p_h, pointer data ) { if(vid_w > (drw_w << 3)) drw_w = vid_w >> 3; if(vid_h > (drw_h << 3)) drw_h = vid_h >> 3; *p_w = drw_w; *p_h = drw_h; } /* * CopyData */ static void NVCopyData422 ( 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; } } /* * CopyMungedData */ static void NVCopyData420 ( 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) { #if X_BYTE_ORDER == X_BIG_ENDIAN dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0]; dst[1] = (s1[2] << 24) | (s1[3] << 8) | (s3[1] << 16) | s2[1]; dst[2] = (s1[4] << 24) | (s1[5] << 8) | (s3[2] << 16) | s2[2]; dst[3] = (s1[6] << 24) | (s1[7] << 8) | (s3[3] << 16) | s2[3]; #else 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); #endif dst += 4; s2 += 4; s3 += 4; s1 += 8; i -= 4; } while(i--) { #if X_BYTE_ORDER == X_BIG_ENDIAN dst[0] = (s1[0] << 24) | (s1[1] << 8) | (s3[0] << 16) | s2[0]; #else dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24); #endif dst++; s2++; s3++; s1 += 2; } dst1 += dstPitch; src1 += srcPitch; if(j & 1) { src2 += srcPitch2; src3 += srcPitch2; } } } /* * PutImage */ static int NVPutImage ( ScrnInfoPtr pScrnInfo, 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 ) { NVPortPrivPtr pPriv = (NVPortPrivPtr)data; NVPtr pNv = NVPTR(pScrnInfo); INT32 xa, xb, ya, yb; unsigned char *dst_start; int pitch, newSize, offset, s2offset, s3offset; int srcPitch, srcPitch2, dstPitch; int top, left, npixels, nlines, bpp; Bool skip = FALSE; BoxRec dstBox; CARD32 tmp; /* * s2offset, s3offset - byte offsets into U and V plane of the * source where copying starts. Y plane is * done by editing "buf". * * offset - byte offset to the first line of the destination. * * dst_start - byte address to the first displayed pel. * */ if(pPriv->grabbedByV4L) return Success; /* make the compiler happy */ s2offset = s3offset = srcPitch2 = 0; if(src_w > (drw_w << 3)) drw_w = src_w >> 3; if(src_h > (drw_h << 3)) drw_h = src_h >> 3; /* Clip */ xa = src_x; xb = src_x + src_w; ya = src_y; yb = src_y + src_h; dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, width, height)) return Success; dstBox.x1 -= pScrnInfo->frameX0; dstBox.x2 -= pScrnInfo->frameX0; dstBox.y1 -= pScrnInfo->frameY0; dstBox.y2 -= pScrnInfo->frameY0; bpp = pScrnInfo->bitsPerPixel >> 3; pitch = bpp * pScrnInfo->displayWidth; dstPitch = ((width << 1) + 63) & ~63; switch(id) { case FOURCC_YV12: case FOURCC_I420: srcPitch = (width + 3) & ~3; /* of luma */ s2offset = srcPitch * height; srcPitch2 = ((width >> 1) + 3) & ~3; s3offset = (srcPitch2 * (height >> 1)) + s2offset; break; case FOURCC_UYVY: case FOURCC_YUY2: default: srcPitch = (width << 1); break; } newSize = height * dstPitch / bpp; if(pPriv->doubleBuffer) newSize <<= 1; pPriv->linear = NVAllocateOverlayMemory(pScrnInfo, pPriv->linear, newSize); if(!pPriv->linear) return BadAlloc; offset = pPriv->linear->offset * bpp; if(pPriv->doubleBuffer) { RIVA_HW_INST *pRiva = &(pNv->riva); int mask = 1 << (pPriv->currentBuffer << 2); #if 0 /* burn the CPU until the next buffer is available */ while(pRiva->PMC[0x00008700/4] & mask); #else /* overwrite the newest buffer if there's not one free */ if(pRiva->PMC[0x00008700/4] & mask) { if(!pPriv->currentBuffer) offset += (newSize * bpp) >> 1; skip = TRUE; } else #endif if(pPriv->currentBuffer) offset += (newSize * bpp) >> 1; } dst_start = pNv->FbStart + offset; /* copy data */ top = ya >> 16; left = (xa >> 16) & ~1; npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; switch(id) { case FOURCC_YV12: case FOURCC_I420: top &= ~1; dst_start += (left << 1) + (top * dstPitch); tmp = ((top >> 1) * srcPitch2) + (left >> 1); s2offset += tmp; s3offset += tmp; if(id == FOURCC_I420) { tmp = s2offset; s2offset = s3offset; s3offset = tmp; } nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top; NVCopyData420(buf + (top * srcPitch) + left, buf + s2offset, buf + s3offset, dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels); break; case FOURCC_UYVY: case FOURCC_YUY2: default: left <<= 1; buf += (top * srcPitch) + left; nlines = ((yb + 0xffff) >> 16) - top; dst_start += left + (top * dstPitch); NVCopyData422(buf, dst_start, srcPitch, dstPitch, nlines, npixels); break; } if(!skip) { NVPutOverlayImage(pScrnInfo, offset, id, dstPitch, &dstBox, xa, ya, xb, yb, width, height, src_w, src_h, drw_w, drw_h, clipBoxes); pPriv->currentBuffer ^= 1; } return Success; } /* * QueryImageAttributes */ static int NVQueryImageAttributes ( ScrnInfoPtr pScrnInfo, int id, unsigned short *w, unsigned short *h, int *pitches, int *offsets ) { int size, tmp; if(*w > 2046) *w = 2046; if(*h > 2046) *h = 2046; *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 NVVideoTimerCallback ( ScrnInfoPtr pScrnInfo, Time currentTime ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pOverPriv = NULL; pNv->VideoTimerCallback = NULL; if(!pScrnInfo->vtSema) return; if(pNv->overlayAdaptor) { pOverPriv = GET_OVERLAY_PRIVATE(pNv); if(!pOverPriv->videoStatus) pOverPriv = NULL; } if(pOverPriv) { if(pOverPriv->videoTime < currentTime) { if(pOverPriv->videoStatus & OFF_TIMER) { NVStopOverlay(pScrnInfo); pOverPriv->videoStatus = FREE_TIMER; pOverPriv->videoTime = currentTime + FREE_DELAY; pNv->VideoTimerCallback = NVVideoTimerCallback; } else if(pOverPriv->videoStatus & FREE_TIMER) { NVFreeOverlayMemory(pScrnInfo); pOverPriv->videoStatus = 0; } } else pNv->VideoTimerCallback = NVVideoTimerCallback; } } /***** Exported offscreen surface stuff ****/ static int NVAllocSurface ( ScrnInfoPtr pScrnInfo, int id, unsigned short w, unsigned short h, XF86SurfacePtr surface ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); CARD8 *address; int size, bpp; bpp = pScrnInfo->bitsPerPixel >> 3; if(pPriv->grabbedByV4L) return BadAlloc; if((w > 2046) || (h > 2046)) return BadValue; w = (w + 1) & ~1; pPriv->pitch = ((w << 1) + 63) & ~63; size = h * pPriv->pitch / bpp; pPriv->linear = NVAllocateOverlayMemory(pScrnInfo, pPriv->linear, size); if(!pPriv->linear) return BadAlloc; pPriv->offset = pPriv->linear->offset * bpp; address = pPriv->offset + pNv->FbStart; surface->width = w; surface->height = h; surface->pScrn = pScrnInfo; surface->pitches = &pPriv->pitch; surface->offsets = &pPriv->offset; surface->devPrivate.ptr = (pointer)pPriv; surface->id = id; /* grab the video */ NVStopOverlay(pScrnInfo); pPriv->videoStatus = 0; REGION_EMPTY(pScrnInfo->pScreen, &pPriv->clip); pNv->VideoTimerCallback = NULL; pPriv->grabbedByV4L = TRUE; return Success; } static int NVStopSurface (XF86SurfacePtr surface) { NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); if(pPriv->grabbedByV4L && pPriv->videoStatus) { NVStopOverlay(surface->pScrn); pPriv->videoStatus = 0; } return Success; } static int NVFreeSurface (XF86SurfacePtr surface) { NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); if(pPriv->grabbedByV4L) { NVStopSurface(surface); NVFreeOverlayMemory(surface->pScrn); pPriv->grabbedByV4L = FALSE; } return Success; } static int NVGetSurfaceAttribute ( ScrnInfoPtr pScrnInfo, Atom attribute, INT32 *value ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); return NVGetPortAttribute(pScrnInfo, attribute, value, (pointer)pPriv); } static int NVSetSurfaceAttribute( ScrnInfoPtr pScrnInfo, Atom attribute, INT32 value ) { NVPtr pNv = NVPTR(pScrnInfo); NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv); return NVSetPortAttribute(pScrnInfo, attribute, value, (pointer)pPriv); } static int NVDisplaySurface ( 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 ) { ScrnInfoPtr pScrnInfo = surface->pScrn; NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr); INT32 xa, xb, ya, yb; BoxRec dstBox; if(!pPriv->grabbedByV4L) return Success; if(src_w > (drw_w << 3)) drw_w = src_w >> 3; if(src_h > (drw_h << 3)) drw_h = src_h >> 3; /* Clip */ xa = src_x; xb = src_x + src_w; ya = src_y; yb = src_y + src_h; dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w; dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, surface->width, surface->height)) { return Success; } dstBox.x1 -= pScrnInfo->frameX0; dstBox.x2 -= pScrnInfo->frameX0; dstBox.y1 -= pScrnInfo->frameY0; dstBox.y2 -= pScrnInfo->frameY0; pPriv->currentBuffer = 0; NVPutOverlayImage (pScrnInfo, surface->offsets[0], surface->id, surface->pitches[0], &dstBox, xa, ya, xb, yb, surface->width, surface->height, src_w, src_h, drw_w, drw_h, clipBoxes); return Success; } XF86OffscreenImageRec NVOffscreenImages[2] = { { &NVImages[0], VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, NVAllocSurface, NVFreeSurface, NVDisplaySurface, NVStopSurface, NVGetSurfaceAttribute, NVSetSurfaceAttribute, 2046, 2046, NUM_ATTRIBUTES - 1, &NVAttributes[1] }, { &NVImages[2], VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT, NVAllocSurface, NVFreeSurface, NVDisplaySurface, NVStopSurface, NVGetSurfaceAttribute, NVSetSurfaceAttribute, 2046, 2046, NUM_ATTRIBUTES - 1, &NVAttributes[1] }, }; static void NVInitOffscreenImages (ScreenPtr pScreen) { xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2); } #endif