summaryrefslogtreecommitdiff
path: root/src/r128_video.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
commitd09f463a5d1ce73e0b65d5276fbcca393fa2da46 (patch)
treebb664ee5f34db07975530b32c7915074aa9515fe /src/r128_video.c
parentd9af6dc32652502d84ea8da5d57a5ab45429c4ad (diff)
Initial revision
Diffstat (limited to 'src/r128_video.c')
-rw-r--r--src/r128_video.c1143
1 files changed, 1143 insertions, 0 deletions
diff --git a/src/r128_video.c b/src/r128_video.c
new file mode 100644
index 0000000..119971f
--- /dev/null
+++ b/src/r128_video.c
@@ -0,0 +1,1143 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_video.c,v 1.26 2003/02/19 01:19:41 dawes Exp $ */
+
+#include "r128.h"
+#include "r128_reg.h"
+
+#ifdef XF86DRI
+#include "r128_common.h"
+#include "r128_sarea.h"
+#endif
+
+#include "xf86.h"
+#include "dixstruct.h"
+
+#include "Xv.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)
+
+#ifndef XvExtension
+void R128InitVideo(ScreenPtr pScreen) {}
+#else
+
+static XF86VideoAdaptorPtr R128SetupImageVideo(ScreenPtr);
+static int R128SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
+static int R128GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
+static void R128StopVideo(ScrnInfoPtr, pointer, Bool);
+static void R128QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
+ unsigned int *, unsigned int *, pointer);
+static int R128PutImage(ScrnInfoPtr, short, short, short, short, short,
+ short, short, short, int, unsigned char*, short,
+ short, Bool, RegionPtr, pointer);
+static int R128QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
+ unsigned short *, int *, int *);
+
+
+static void R128ResetVideo(ScrnInfoPtr);
+
+static void R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now);
+
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer;
+
+
+typedef struct {
+ int brightness;
+ int saturation;
+ Bool doubleBuffer;
+ unsigned char currentBuffer;
+ FBLinearPtr linear;
+ RegionRec clip;
+ CARD32 colorKey;
+ CARD32 videoStatus;
+ Time offTime;
+ Time freeTime;
+} R128PortPrivRec, *R128PortPrivPtr;
+
+
+void R128InitVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ R128InfoPtr info = R128PTR(pScrn);
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ int num_adaptors;
+
+ if(info->accel && info->accel->FillSolidRects)
+ newAdaptor = R128SetupImageVideo(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);
+}
+
+#define MAXWIDTH 2048
+#define MAXHEIGHT 2048
+
+/* client libraries expect an encoding */
+static XF86VideoEncodingRec DummyEncoding =
+{
+ 0,
+ "XV_IMAGE",
+ MAXWIDTH, MAXHEIGHT,
+ {1, 1}
+};
+
+#define NUM_FORMATS 12
+
+static XF86VideoFormatRec Formats[NUM_FORMATS] =
+{
+ {8, TrueColor}, {8, DirectColor}, {8, PseudoColor},
+ {8, GrayScale}, {8, StaticGray}, {8, StaticColor},
+ {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
+ {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
+};
+
+
+#define NUM_ATTRIBUTES 4
+
+static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
+{
+ {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
+ {XvSettable | XvGettable, -64, 63, "XV_BRIGHTNESS"},
+ {XvSettable | XvGettable, 0, 31, "XV_SATURATION"},
+ {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
+};
+
+#define NUM_IMAGES 4
+
+static XF86ImageRec Images[NUM_IMAGES] =
+{
+ XVIMAGE_YUY2,
+ XVIMAGE_UYVY,
+ XVIMAGE_YV12,
+ XVIMAGE_I420
+};
+
+static void
+R128ResetVideo(ScrnInfoPtr pScrn)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
+
+
+ OUTREG(R128_OV0_SCALE_CNTL, 0x80000000);
+ OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0);
+ OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0); /* maybe */
+ OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f);
+ OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
+ (pPriv->saturation << 8) |
+ (pPriv->saturation << 16));
+ OUTREG(R128_OV0_GRAPHICS_KEY_MSK, (1 << pScrn->depth) - 1);
+ OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey);
+ OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE);
+ OUTREG(R128_OV0_TEST, 0);
+}
+
+
+static XF86VideoAdaptorPtr
+R128AllocAdaptor(ScrnInfoPtr pScrn)
+{
+ XF86VideoAdaptorPtr adapt;
+ R128InfoPtr info = R128PTR(pScrn);
+ R128PortPrivPtr pPriv;
+
+ if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
+ return NULL;
+
+ if(!(pPriv = xcalloc(1, sizeof(R128PortPrivRec) + sizeof(DevUnion))))
+ {
+ xfree(adapt);
+ return NULL;
+ }
+
+ adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
+ adapt->pPortPrivates[0].ptr = (pointer)pPriv;
+
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvSaturation = MAKE_ATOM("XV_SATURATION");
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
+
+ pPriv->colorKey = info->videoKey;
+ pPriv->doubleBuffer = TRUE;
+ pPriv->videoStatus = 0;
+ pPriv->brightness = 0;
+ pPriv->saturation = 16;
+ pPriv->currentBuffer = 0;
+
+ return adapt;
+}
+
+static XF86VideoAdaptorPtr
+R128SetupImageVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ R128InfoPtr info = R128PTR(pScrn);
+ R128PortPrivPtr pPriv;
+ XF86VideoAdaptorPtr adapt;
+
+ if(!(adapt = R128AllocAdaptor(pScrn)))
+ return NULL;
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adapt->name = "ATI Rage128 Video Overlay";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = &DummyEncoding;
+ adapt->nFormats = NUM_FORMATS;
+ adapt->pFormats = Formats;
+ adapt->nPorts = 1;
+ adapt->nAttributes = NUM_ATTRIBUTES;
+ adapt->pAttributes = Attributes;
+ adapt->nImages = NUM_IMAGES;
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo = R128StopVideo;
+ adapt->SetPortAttribute = R128SetPortAttribute;
+ adapt->GetPortAttribute = R128GetPortAttribute;
+ adapt->QueryBestSize = R128QueryBestSize;
+ adapt->PutImage = R128PutImage;
+ adapt->QueryImageAttributes = R128QueryImageAttributes;
+
+ info->adaptor = adapt;
+
+ pPriv = (R128PortPrivPtr)(adapt->pPortPrivates[0].ptr);
+ REGION_INIT(pScreen, &(pPriv->clip), NullBox, 0);
+
+ R128ResetVideo(pScrn);
+
+ return adapt;
+}
+
+/* I really should stick this in miregion */
+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 = (pointer)REGION_RECTS(A);
+ dataB = (pointer)REGION_RECTS(B);
+
+ while(num--) {
+ if((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
+ return FALSE;
+ dataA += 2;
+ dataB += 2;
+ }
+
+ return TRUE;
+}
+
+
+/* R128ClipVideo -
+
+ 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 (xa, ya
+ inclusive, xb, yb exclusive) and returned are the new source
+ boundaries in 16.16 fixed point.
+*/
+
+#define DummyScreen screenInfo.screens[0]
+
+static Bool
+R128ClipVideo(
+ BoxPtr dst,
+ INT32 *xa,
+ INT32 *xb,
+ INT32 *ya,
+ INT32 *yb,
+ RegionPtr reg,
+ INT32 width,
+ INT32 height
+){
+ INT32 vscale, hscale, delta;
+ BoxPtr extents = REGION_EXTENTS(DummyScreen, reg);
+ int diff;
+
+ hscale = ((*xb - *xa) << 16) / (dst->x2 - dst->x1);
+ vscale = ((*yb - *ya) << 16) / (dst->y2 - dst->y1);
+
+ *xa <<= 16; *xb <<= 16;
+ *ya <<= 16; *yb <<= 16;
+
+ diff = extents->x1 - dst->x1;
+ if(diff > 0) {
+ dst->x1 = extents->x1;
+ *xa += diff * hscale;
+ }
+ diff = dst->x2 - extents->x2;
+ if(diff > 0) {
+ dst->x2 = extents->x2;
+ *xb -= diff * hscale;
+ }
+ diff = extents->y1 - dst->y1;
+ if(diff > 0) {
+ dst->y1 = extents->y1;
+ *ya += diff * vscale;
+ }
+ diff = dst->y2 - extents->y2;
+ if(diff > 0) {
+ dst->y2 = extents->y2;
+ *yb -= diff * vscale;
+ }
+
+ if(*xa < 0) {
+ diff = (- *xa + hscale - 1)/ hscale;
+ dst->x1 += diff;
+ *xa += diff * hscale;
+ }
+ delta = *xb - (width << 16);
+ if(delta > 0) {
+ diff = (delta + hscale - 1)/ hscale;
+ dst->x2 -= diff;
+ *xb -= diff * hscale;
+ }
+ if(*xa >= *xb) return FALSE;
+
+ if(*ya < 0) {
+ diff = (- *ya + vscale - 1)/ vscale;
+ dst->y1 += diff;
+ *ya += diff * vscale;
+ }
+ delta = *yb - (height << 16);
+ if(delta > 0) {
+ diff = (delta + vscale - 1)/ vscale;
+ dst->y2 -= diff;
+ *yb -= diff * vscale;
+ }
+ if(*ya >= *yb) 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
+R128StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+ if(cleanup) {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ OUTREG(R128_OV0_SCALE_CNTL, 0);
+ if (info->cursor_start)
+ xf86ForceHWCursor (pScrn->pScreen, FALSE);
+ }
+ 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
+R128SetPortAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value,
+ pointer data
+){
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
+
+ if(attribute == xvBrightness) {
+ if((value < -64) || (value > 63))
+ return BadValue;
+ pPriv->brightness = value;
+
+ OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
+ (pPriv->saturation << 8) |
+ (pPriv->saturation << 16));
+ } else
+ if(attribute == xvSaturation) {
+ if((value < 0) || (value > 31))
+ return BadValue;
+ pPriv->saturation = value;
+
+ OUTREG(R128_OV0_COLOUR_CNTL, (pPriv->brightness & 0x7f) |
+ (pPriv->saturation << 8) |
+ (pPriv->saturation << 16));
+ } else
+ if(attribute == xvDoubleBuffer) {
+ if((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->doubleBuffer = value;
+ } else
+ if(attribute == xvColorKey) {
+ pPriv->colorKey = value;
+ OUTREG(R128_OV0_GRAPHICS_KEY_CLR, pPriv->colorKey);
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ } else return BadMatch;
+
+ return Success;
+}
+
+static int
+R128GetPortAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data
+){
+ R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
+
+ if(attribute == xvBrightness) {
+ *value = pPriv->brightness;
+ } else
+ if(attribute == xvSaturation) {
+ *value = pPriv->saturation;
+ } else
+ if(attribute == xvDoubleBuffer) {
+ *value = pPriv->doubleBuffer ? 1 : 0;
+ } else
+ if(attribute == xvColorKey) {
+ *value = pPriv->colorKey;
+ } else return BadMatch;
+
+ return Success;
+}
+
+
+static void
+R128QueryBestSize(
+ 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
+){
+ if(vid_w > (drw_w << 4))
+ drw_w = vid_w >> 4;
+ if(vid_h > (drw_h << 4))
+ drw_h = vid_h >> 4;
+
+ *p_w = drw_w;
+ *p_h = drw_h;
+}
+
+
+/*
+ *
+ * R128DMA - abuse the texture blit ioctl to transfer rectangular blocks
+ *
+ * The block is split into 'passes' pieces of 'hpass' lines which fit entirely
+ * into an indirect buffer
+ *
+ */
+
+static Bool
+R128DMA(
+ R128InfoPtr info,
+ unsigned char *src,
+ unsigned char *dst,
+ int srcPitch,
+ int dstPitch,
+ int h,
+ int w
+){
+
+#ifdef XF86DRI
+
+#define BUFSIZE (R128_BUFFER_SIZE - R128_HOSTDATA_BLIT_OFFSET)
+#define MAXPASSES (MAXHEIGHT/(BUFSIZE/(MAXWIDTH*2))+1)
+
+ unsigned char *buf;
+ int err=-1, i, idx, offset, hpass, passes, srcpassbytes, dstpassbytes;
+ int sizes[MAXPASSES], list[MAXPASSES];
+ drmDMAReq req;
+ drmR128Blit blit;
+
+ /* Verify conditions and bail out as early as possible */
+ if (!info->directRenderingEnabled || !info->DMAForXv)
+ return FALSE;
+
+ if ((hpass = min(h,(BUFSIZE/w))) == 0)
+ return FALSE;
+
+ if ((passes = (h+hpass-1)/hpass) > MAXPASSES)
+ return FALSE;
+
+ /* Request indirect buffers */
+ srcpassbytes = w*hpass;
+
+ req.context = info->drmCtx;
+ req.send_count = 0;
+ req.send_list = NULL;
+ req.send_sizes = NULL;
+ req.flags = DRM_DMA_LARGER_OK;
+ req.request_count = passes;
+ req.request_size = srcpassbytes + R128_HOSTDATA_BLIT_OFFSET;
+ req.request_list = &list[0];
+ req.request_sizes = &sizes[0];
+ req.granted_count = 0;
+
+ if (drmDMA(info->drmFD, &req))
+ return FALSE;
+
+ if (req.granted_count < passes) {
+ drmFreeBufs(info->drmFD, req.granted_count, req.request_list);
+ return FALSE;
+ }
+
+ /* Copy parts of the block into buffers and fire them */
+ dstpassbytes = hpass*dstPitch;
+ dstPitch /= 8;
+
+ for (i=0, offset=dst-info->FB; i<passes; i++, offset+=dstpassbytes) {
+ if (i == (passes-1) && (h % hpass) != 0) {
+ hpass = h % hpass;
+ srcpassbytes = w*hpass;
+ }
+
+ idx = req.request_list[i];
+ buf = (unsigned char *) info->buffers->list[idx].address + R128_HOSTDATA_BLIT_OFFSET;
+
+ if (srcPitch == w) {
+ memcpy(buf, src, srcpassbytes);
+ src += srcpassbytes;
+ } else {
+ int count = hpass;
+ while(count--) {
+ memcpy(buf, src, w);
+ src += srcPitch;
+ buf += w;
+ }
+ }
+
+ blit.idx = idx;
+ blit.offset = offset;
+ blit.pitch = dstPitch;
+ blit.format = (R128_DATATYPE_CI8 >> 16);
+ blit.x = (offset % 32);
+ blit.y = 0;
+ blit.width = w;
+ blit.height = hpass;
+
+ if ((err = drmCommandWrite(info->drmFD, DRM_R128_BLIT,
+ &blit, sizeof(drmR128Blit))) < 0)
+ break;
+ }
+
+ drmFreeBufs(info->drmFD, req.granted_count, req.request_list);
+
+ return (err==0) ? TRUE : FALSE;
+
+#else
+
+ /* This is to avoid cluttering the rest of the code with '#ifdef XF86DRI' */
+ return FALSE;
+
+#endif /* XF86DRI */
+
+}
+
+
+static void
+R128CopyData422(
+ R128InfoPtr info,
+ unsigned char *src,
+ unsigned char *dst,
+ int srcPitch,
+ int dstPitch,
+ int h,
+ int w
+){
+ w <<= 1;
+
+ /* Attempt data transfer with DMA and fall back to memcpy */
+
+ if (!R128DMA(info, src, dst, srcPitch, dstPitch, h, w)) {
+ while(h--) {
+ memcpy(dst, src, w);
+ src += srcPitch;
+ dst += dstPitch;
+ }
+ }
+}
+
+static void
+R128CopyData420(
+ R128InfoPtr info,
+ unsigned char *src1,
+ unsigned char *src2,
+ unsigned char *src3,
+ unsigned char *dst1,
+ unsigned char *dst2,
+ unsigned char *dst3,
+ int srcPitch,
+ int srcPitch2,
+ int dstPitch,
+ int h,
+ int w
+){
+ int count;
+
+ /* Attempt data transfer with DMA and fall back to memcpy */
+
+ if (!R128DMA(info, src1, dst1, srcPitch, dstPitch, h, w)) {
+ count = h;
+ while(count--) {
+ memcpy(dst1, src1, w);
+ src1 += srcPitch;
+ dst1 += dstPitch;
+ }
+ }
+
+ w >>= 1;
+ h >>= 1;
+ dstPitch >>= 1;
+
+ if (!R128DMA(info, src2, dst2, srcPitch2, dstPitch, h, w)) {
+ count = h;
+ while(count--) {
+ memcpy(dst2, src2, w);
+ src2 += srcPitch2;
+ dst2 += dstPitch;
+ }
+ }
+
+ if (!R128DMA(info, src3, dst3, srcPitch2, dstPitch, h, w)) {
+ count = h;
+ while(count--) {
+ memcpy(dst3, src3, w);
+ src3 += srcPitch2;
+ dst3 += dstPitch;
+ }
+ }
+}
+
+
+static FBLinearPtr
+R128AllocateMemory(
+ 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
+R128DisplayVideo422(
+ ScrnInfoPtr pScrn,
+ int id,
+ int offset,
+ short width, short height,
+ int pitch,
+ int left, int right, int top,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+){
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ int v_inc, h_inc, step_by, tmp;
+ int p1_h_accum_init, p23_h_accum_init;
+ int p1_v_accum_init;
+
+ v_inc = (src_h << 20) / drw_h;
+ h_inc = (src_w << 12) / drw_w;
+ step_by = 1;
+
+ while(h_inc >= (2 << 12)) {
+ step_by++;
+ h_inc >>= 1;
+ }
+
+ /* keep everything in 16.16 */
+
+ offset += ((left >> 16) & ~7) << 1;
+
+ tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
+ p1_h_accum_init = ((tmp << 4) & 0x000f8000) |
+ ((tmp << 12) & 0xf0000000);
+
+ tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
+ p23_h_accum_init = ((tmp << 4) & 0x000f8000) |
+ ((tmp << 12) & 0x70000000);
+
+ tmp = (top & 0x0000ffff) + 0x00018000;
+ p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
+
+ left = (left >> 16) & 7;
+
+ OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
+ while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
+
+ OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
+ OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
+ OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
+ OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16));
+ OUTREG(R128_OV0_V_INC, v_inc);
+ OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
+ OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
+ OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
+ left >>= 1; width >>= 1;
+ OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16));
+ OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16));
+ OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset & 0xfffffff0);
+ OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
+ OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0);
+ OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
+ OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
+
+ if(id == FOURCC_UYVY)
+ OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8C03);
+ else
+ OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03);
+
+ OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
+}
+
+static void
+R128DisplayVideo420(
+ ScrnInfoPtr pScrn,
+ short width, short height,
+ int pitch,
+ int offset1, int offset2, int offset3,
+ int left, int right, int top,
+ BoxPtr dstBox,
+ short src_w, short src_h,
+ short drw_w, short drw_h
+){
+ R128InfoPtr info = R128PTR(pScrn);
+ unsigned char *R128MMIO = info->MMIO;
+ int v_inc, h_inc, step_by, tmp, leftUV;
+ int p1_h_accum_init, p23_h_accum_init;
+ int p1_v_accum_init, p23_v_accum_init;
+
+ v_inc = (src_h << 20) / drw_h;
+ h_inc = (src_w << 12) / drw_w;
+ step_by = 1;
+
+ while(h_inc >= (2 << 12)) {
+ step_by++;
+ h_inc >>= 1;
+ }
+
+ /* keep everything in 16.16 */
+
+ offset1 += (left >> 16) & ~15;
+ offset2 += (left >> 17) & ~15;
+ offset3 += (left >> 17) & ~15;
+
+ tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3);
+ p1_h_accum_init = ((tmp << 4) & 0x000f8000) |
+ ((tmp << 12) & 0xf0000000);
+
+ tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (h_inc << 2);
+ p23_h_accum_init = ((tmp << 4) & 0x000f8000) |
+ ((tmp << 12) & 0x70000000);
+
+ tmp = (top & 0x0000ffff) + 0x00018000;
+ p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
+
+ tmp = ((top >> 1) & 0x0000ffff) + 0x00018000;
+ p23_v_accum_init = ((tmp << 4) & 0x01ff8000) | 0x00000001;
+
+ leftUV = (left >> 17) & 15;
+ left = (left >> 16) & 15;
+
+ OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
+ while(!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)));
+
+ OUTREG(R128_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
+ OUTREG(R128_OV0_STEP_BY, step_by | (step_by << 8));
+ OUTREG(R128_OV0_Y_X_START, dstBox->x1 | (dstBox->y1 << 16));
+ OUTREG(R128_OV0_Y_X_END, dstBox->x2 | (dstBox->y2 << 16));
+ OUTREG(R128_OV0_V_INC, v_inc);
+ OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
+ src_h = (src_h + 1) >> 1;
+ OUTREG(R128_OV0_P23_BLANK_LINES_AT_TOP, 0x000007ff | ((src_h - 1) << 16));
+ OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, pitch);
+ OUTREG(R128_OV0_VID_BUF_PITCH1_VALUE, pitch >> 1);
+ OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
+ width >>= 1;
+ OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (leftUV << 16));
+ OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (leftUV << 16));
+ OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0);
+ OUTREG(R128_OV0_VID_BUF1_BASE_ADRS, (offset2 & 0xfffffff0) | 0x00000001);
+ OUTREG(R128_OV0_VID_BUF2_BASE_ADRS, (offset3 & 0xfffffff0) | 0x00000001);
+ OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
+ OUTREG(R128_OV0_P23_V_ACCUM_INIT, p23_v_accum_init);
+ OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
+ OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
+ OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8A03);
+
+ OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
+}
+
+
+
+static int
+R128PutImage(
+ 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
+){
+ R128InfoPtr info = R128PTR(pScrn);
+ R128PortPrivPtr pPriv = (R128PortPrivPtr)data;
+ INT32 xa, xb, ya, yb;
+ int pitch, new_size, offset, s1offset, s2offset, s3offset;
+ int srcPitch, srcPitch2, dstPitch;
+ int d1line, d2line, d3line, d1offset, d2offset, d3offset;
+ int top, left, npixels, nlines, bpp;
+ BoxRec dstBox;
+ CARD32 tmp;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ unsigned char *R128MMIO = info->MMIO;
+ CARD32 config_cntl = INREG(R128_CONFIG_CNTL);
+
+ /* We need to disable byte swapping, or the data gets mangled */
+ OUTREG(R128_CONFIG_CNTL, config_cntl &
+ ~(APER_0_BIG_ENDIAN_16BPP_SWAP | APER_0_BIG_ENDIAN_32BPP_SWAP));
+#endif
+
+ /*
+ * s1offset, s2offset, s3offset - byte offsets to the Y, U and V planes
+ * of the source.
+ *
+ * d1offset, d2offset, d3offset - byte offsets to the Y, U and V planes
+ * of the destination.
+ *
+ * offset - byte offset within the framebuffer to where the destination
+ * is stored.
+ *
+ * d1line, d2line, d3line - byte offsets within the destination to the
+ * first displayed scanline in each plane.
+ *
+ */
+
+ if(src_w > (drw_w << 4))
+ drw_w = src_w >> 4;
+ if(src_h > (drw_h << 4))
+ drw_h = src_h >> 4;
+
+ /* 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(!R128ClipVideo(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, width, height))
+ return Success;
+
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+
+ bpp = pScrn->bitsPerPixel >> 3;
+ pitch = bpp * pScrn->displayWidth;
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ srcPitch = (width + 3) & ~3;
+ srcPitch2 = ((width >> 1) + 3) & ~3;
+ dstPitch = (width + 31) & ~31; /* of luma */
+ new_size = ((dstPitch * (height + (height >> 1))) + bpp - 1) / bpp;
+ s1offset = 0;
+ s2offset = srcPitch * height;
+ s3offset = (srcPitch2 * (height >> 1)) + s2offset;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ srcPitch = width << 1;
+ srcPitch2 = 0;
+ dstPitch = ((width << 1) + 15) & ~15;
+ new_size = ((dstPitch * height) + bpp - 1) / bpp;
+ s1offset = 0;
+ s2offset = 0;
+ s3offset = 0;
+ break;
+ }
+
+ if(!(pPriv->linear = R128AllocateMemory(pScrn, pPriv->linear,
+ pPriv->doubleBuffer ? (new_size << 1) : new_size)))
+ {
+ return BadAlloc;
+ }
+
+ pPriv->currentBuffer ^= 1;
+
+ /* copy data */
+ top = ya >> 16;
+ left = (xa >> 16) & ~1;
+ npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left;
+
+ offset = pPriv->linear->offset * bpp;
+ if(pPriv->doubleBuffer)
+ offset += pPriv->currentBuffer * new_size * bpp;
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ d1line = top * dstPitch;
+ d2line = (height * dstPitch) + ((top >> 1) * (dstPitch >> 1));
+ d3line = d2line + ((height >> 1) * (dstPitch >> 1));
+
+ top &= ~1;
+
+ d1offset = (top * dstPitch) + left + offset;
+ d2offset = d2line + (left >> 1) + offset;
+ d3offset = d3line + (left >> 1) + offset;
+
+ s1offset += (top * srcPitch) + left;
+ tmp = ((top >> 1) * srcPitch2) + (left >> 1);
+ s2offset += tmp;
+ s3offset += tmp;
+ if(id == FOURCC_YV12) {
+ tmp = s2offset;
+ s2offset = s3offset;
+ s3offset = tmp;
+ }
+
+ nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
+ R128CopyData420(info, buf + s1offset, buf + s2offset, buf + s3offset,
+ info->FB+d1offset, info->FB+d2offset, info->FB+d3offset,
+ srcPitch, srcPitch2, dstPitch, nlines, npixels);
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ left <<= 1;
+ d1line = top * dstPitch;
+ d2line = 0;
+ d3line = 0;
+ d1offset = d1line + left + offset;
+ d2offset = 0;
+ d3offset = 0;
+ s1offset += (top * srcPitch) + left;
+ nlines = ((yb + 0xffff) >> 16) - top;
+ R128CopyData422(info, buf + s1offset, info->FB + d1offset,
+ srcPitch, dstPitch, nlines, npixels);
+ break;
+ }
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ /* restore byte swapping */
+ OUTREG(R128_CONFIG_CNTL, config_cntl);
+#endif
+
+ /* update cliplist */
+ if(!RegionsEqual(&pPriv->clip, clipBoxes)) {
+ REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+ /* draw these */
+ (*info->accel->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy,
+ (CARD32)~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+ }
+
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ R128DisplayVideo420(pScrn, width, height, dstPitch,
+ offset + d1line, offset + d2line, offset + d3line,
+ xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ R128DisplayVideo422(pScrn, id, offset + d1line, width, height, dstPitch,
+ xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
+ break;
+ }
+
+ if (info->cursor_start && !(pPriv->videoStatus & CLIENT_VIDEO_ON))
+ xf86ForceHWCursor (pScrn->pScreen, TRUE);
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+
+ info->VideoTimerCallback = R128VideoTimerCallback;
+
+ return Success;
+}
+
+
+static int
+R128QueryImageAttributes(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets
+){
+ int size, tmp;
+
+ if(*w > MAXWIDTH) *w = MAXWIDTH;
+ if(*h > MAXHEIGHT) *h = MAXHEIGHT;
+
+ *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
+R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now)
+{
+ R128InfoPtr info = R128PTR(pScrn);
+ R128PortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
+
+ if(pPriv->videoStatus & TIMER_MASK) {
+ if(pPriv->videoStatus & OFF_TIMER) {
+ if(pPriv->offTime < now) {
+ unsigned char *R128MMIO = info->MMIO;
+ OUTREG(R128_OV0_SCALE_CNTL, 0);
+ if (info->cursor_start && pPriv->videoStatus & CLIENT_VIDEO_ON)
+ xf86ForceHWCursor (pScrn->pScreen, FALSE);
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = now + FREE_DELAY;
+ }
+ } else { /* FREE_TIMER */
+ if(pPriv->freeTime < now) {
+ if(pPriv->linear) {
+ xf86FreeOffscreenLinear(pPriv->linear);
+ pPriv->linear = NULL;
+ }
+ if (info->cursor_start && pPriv->videoStatus & CLIENT_VIDEO_ON)
+ xf86ForceHWCursor (pScrn->pScreen, FALSE);
+ pPriv->videoStatus = 0;
+ info->VideoTimerCallback = NULL;
+ }
+ }
+ } else /* shouldn't get here */
+ info->VideoTimerCallback = NULL;
+}
+
+
+#endif /* !XvExtension */