summaryrefslogtreecommitdiff
path: root/src/radeon_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/radeon_video.c
parentd9af6dc32652502d84ea8da5d57a5ab45429c4ad (diff)
Initial revision
Diffstat (limited to 'src/radeon_video.c')
-rw-r--r--src/radeon_video.c1586
1 files changed, 1586 insertions, 0 deletions
diff --git a/src/radeon_video.c b/src/radeon_video.c
new file mode 100644
index 0000000..44ee2e6
--- /dev/null
+++ b/src/radeon_video.c
@@ -0,0 +1,1586 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_video.c,v 1.24 2003/02/19 01:19:43 dawes Exp $ */
+
+#include "radeon.h"
+#include "radeon_macros.h"
+#include "radeon_probe.h"
+#include "radeon_reg.h"
+
+#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)
+
+extern int gRADEONEntityIndex;
+
+#ifndef XvExtension
+void RADEONInitVideo(ScreenPtr pScreen) {}
+#else
+
+static void RADEONInitOffscreenImages(ScreenPtr);
+
+static XF86VideoAdaptorPtr RADEONSetupImageVideo(ScreenPtr);
+static int RADEONSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
+static int RADEONGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
+static void RADEONStopVideo(ScrnInfoPtr, pointer, Bool);
+static void RADEONQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
+ unsigned int *, unsigned int *, pointer);
+static int RADEONPutImage(ScrnInfoPtr, short, short, short, short, short,
+ short, short, short, int, unsigned char*, short,
+ short, Bool, RegionPtr, pointer);
+static int RADEONQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
+ unsigned short *, int *, int *);
+
+
+static void RADEONResetVideo(ScrnInfoPtr);
+
+static void RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now);
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer;
+static Atom xvRedIntensity, xvGreenIntensity, xvBlueIntensity;
+static Atom xvContrast, xvHue, xvColor, xvAutopaintColorkey, xvSetDefaults;
+
+typedef struct {
+ CARD32 transform_index;
+ int brightness;
+ int saturation;
+ int hue;
+ int contrast;
+ int red_intensity;
+ int green_intensity;
+ int blue_intensity;
+ int ecp_div;
+
+ Bool doubleBuffer;
+ unsigned char currentBuffer;
+ RegionRec clip;
+ CARD32 colorKey;
+ CARD32 videoStatus;
+ Time offTime;
+ Time freeTime;
+ Bool autopaint_colorkey;
+} RADEONPortPrivRec, *RADEONPortPrivPtr;
+
+
+#define GET_PORT_PRIVATE(pScrn) \
+ (RADEONPortPrivPtr)((RADEONPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
+
+void RADEONInitVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ int num_adaptors;
+
+ if(info->accel && info->accel->FillSolidRects)
+ {
+ newAdaptor = RADEONSetupImageVideo(pScreen);
+ RADEONInitOffscreenImages(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 =
+{
+ 0,
+ "XV_IMAGE",
+ 2048, 2048,
+ {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 9+3
+
+static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
+{
+ {XvSettable , 0, 1, "XV_SET_DEFAULTS"},
+ {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
+ {XvSettable | XvGettable, 0, ~0, "XV_COLORKEY"},
+ {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_COLOR"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_RED_INTENSITY"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_GREEN_INTENSITY"},
+ {XvSettable | XvGettable, -1000, 1000, "XV_BLUE_INTENSITY"},
+};
+
+#define NUM_IMAGES 4
+
+static XF86ImageRec Images[NUM_IMAGES] =
+{
+ XVIMAGE_YUY2,
+ XVIMAGE_UYVY,
+ XVIMAGE_YV12,
+ XVIMAGE_I420
+};
+
+/* Reference color space transform data */
+typedef struct tagREF_TRANSFORM
+{
+ float RefLuma;
+ float RefRCb;
+ float RefRCr;
+ float RefGCb;
+ float RefGCr;
+ float RefBCb;
+ float RefBCr;
+} REF_TRANSFORM;
+
+/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces */
+REF_TRANSFORM trans[2] =
+{
+ {1.1678, 0.0, 1.6007, -0.3929, -0.8154, 2.0232, 0.0}, /* BT.601 */
+ {1.1678, 0.0, 1.7980, -0.2139, -0.5345, 2.1186, 0.0} /* BT.709 */
+};
+
+
+/* Gamma curve definition */
+typedef struct
+{
+ unsigned int gammaReg;
+ unsigned int gammaSlope;
+ unsigned int gammaOffset;
+} GAMMA_SETTINGS;
+
+/* Recommended gamma curve parameters */
+GAMMA_SETTINGS def_gamma[18] =
+{
+ {RADEON_OV0_GAMMA_000_00F, 0x100, 0x0000},
+ {RADEON_OV0_GAMMA_010_01F, 0x100, 0x0020},
+ {RADEON_OV0_GAMMA_020_03F, 0x100, 0x0040},
+ {RADEON_OV0_GAMMA_040_07F, 0x100, 0x0080},
+ {RADEON_OV0_GAMMA_080_0BF, 0x100, 0x0100},
+ {RADEON_OV0_GAMMA_0C0_0FF, 0x100, 0x0100},
+ {RADEON_OV0_GAMMA_100_13F, 0x100, 0x0200},
+ {RADEON_OV0_GAMMA_140_17F, 0x100, 0x0200},
+ {RADEON_OV0_GAMMA_180_1BF, 0x100, 0x0300},
+ {RADEON_OV0_GAMMA_1C0_1FF, 0x100, 0x0300},
+ {RADEON_OV0_GAMMA_200_23F, 0x100, 0x0400},
+ {RADEON_OV0_GAMMA_240_27F, 0x100, 0x0400},
+ {RADEON_OV0_GAMMA_280_2BF, 0x100, 0x0500},
+ {RADEON_OV0_GAMMA_2C0_2FF, 0x100, 0x0500},
+ {RADEON_OV0_GAMMA_300_33F, 0x100, 0x0600},
+ {RADEON_OV0_GAMMA_340_37F, 0x100, 0x0600},
+ {RADEON_OV0_GAMMA_380_3BF, 0x100, 0x0700},
+ {RADEON_OV0_GAMMA_3C0_3FF, 0x100, 0x0700}
+};
+
+/****************************************************************************
+ * SetTransform *
+ * Function: Calculates and sets color space transform from supplied *
+ * reference transform, gamma, brightness, contrast, hue and *
+ * saturation. *
+ * Inputs: bright - brightness *
+ * cont - contrast *
+ * sat - saturation *
+ * hue - hue *
+ * red_intensity - intensity of red component *
+ * green_intensity - intensity of green component *
+ * blue_intensity - intensity of blue component *
+ * ref - index to the table of refernce transforms *
+ * Outputs: NONE *
+ ****************************************************************************/
+
+static void RADEONSetTransform (ScrnInfoPtr pScrn,
+ float bright,
+ float cont,
+ float sat,
+ float hue,
+ float red_intensity,
+ float green_intensity,
+ float blue_intensity,
+ CARD32 ref)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ float OvHueSin, OvHueCos;
+ float CAdjLuma, CAdjOff;
+ float CAdjRCb, CAdjRCr;
+ float CAdjGCb, CAdjGCr;
+ float CAdjBCb, CAdjBCr;
+ float RedAdj,GreenAdj,BlueAdj;
+ float OvLuma, OvROff, OvGOff, OvBOff;
+ float OvRCb, OvRCr;
+ float OvGCb, OvGCr;
+ float OvBCb, OvBCr;
+ float Loff = 64.0;
+ float Coff = 512.0f;
+
+ CARD32 dwOvLuma, dwOvROff, dwOvGOff, dwOvBOff;
+ CARD32 dwOvRCb, dwOvRCr;
+ CARD32 dwOvGCb, dwOvGCr;
+ CARD32 dwOvBCb, dwOvBCr;
+
+ if (ref >= 2)
+ return;
+
+ OvHueSin = sin(hue);
+ OvHueCos = cos(hue);
+
+ CAdjLuma = cont * trans[ref].RefLuma;
+ CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0;
+ RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0;
+ GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0;
+ BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0;
+
+ CAdjRCb = sat * -OvHueSin * trans[ref].RefRCr;
+ CAdjRCr = sat * OvHueCos * trans[ref].RefRCr;
+ CAdjGCb = sat * (OvHueCos * trans[ref].RefGCb - OvHueSin * trans[ref].RefGCr);
+ CAdjGCr = sat * (OvHueSin * trans[ref].RefGCb + OvHueCos * trans[ref].RefGCr);
+ CAdjBCb = sat * OvHueCos * trans[ref].RefBCb;
+ CAdjBCr = sat * OvHueSin * trans[ref].RefBCb;
+
+#if 0 /* default constants */
+ CAdjLuma = 1.16455078125;
+
+ CAdjRCb = 0.0;
+ CAdjRCr = 1.59619140625;
+ CAdjGCb = -0.39111328125;
+ CAdjGCr = -0.8125;
+ CAdjBCb = 2.01708984375;
+ CAdjBCr = 0;
+#endif
+ OvLuma = CAdjLuma;
+ OvRCb = CAdjRCb;
+ OvRCr = CAdjRCr;
+ OvGCb = CAdjGCb;
+ OvGCr = CAdjGCr;
+ OvBCb = CAdjBCb;
+ OvBCr = CAdjBCr;
+ OvROff = RedAdj + CAdjOff -
+ OvLuma * Loff - (OvRCb + OvRCr) * Coff;
+ OvGOff = GreenAdj + CAdjOff -
+ OvLuma * Loff - (OvGCb + OvGCr) * Coff;
+ OvBOff = BlueAdj + CAdjOff -
+ OvLuma * Loff - (OvBCb + OvBCr) * Coff;
+#if 0 /* default constants */
+ OvROff = -888.5;
+ OvGOff = 545;
+ OvBOff = -1104;
+#endif
+
+ dwOvROff = ((INT32)(OvROff * 2.0)) & 0x1fff;
+ dwOvGOff = ((INT32)(OvGOff * 2.0)) & 0x1fff;
+ dwOvBOff = ((INT32)(OvBOff * 2.0)) & 0x1fff;
+ /*
+ * Whatever docs say about R200 having 3.8 format instead of 3.11
+ * as in Radeon is a lie
+ * Or more precisely the location of bit fields is a lie
+ */
+ if(1 || info->ChipFamily < CHIP_FAMILY_R200)
+ {
+ dwOvLuma =(((INT32)(OvLuma * 2048.0))&0x7fff)<<17;
+ dwOvRCb = (((INT32)(OvRCb * 2048.0))&0x7fff)<<1;
+ dwOvRCr = (((INT32)(OvRCr * 2048.0))&0x7fff)<<17;
+ dwOvGCb = (((INT32)(OvGCb * 2048.0))&0x7fff)<<1;
+ dwOvGCr = (((INT32)(OvGCr * 2048.0))&0x7fff)<<17;
+ dwOvBCb = (((INT32)(OvBCb * 2048.0))&0x7fff)<<1;
+ dwOvBCr = (((INT32)(OvBCr * 2048.0))&0x7fff)<<17;
+ }
+ else
+ {
+ dwOvLuma = (((INT32)(OvLuma * 256.0))&0x7ff)<<20;
+ dwOvRCb = (((INT32)(OvRCb * 256.0))&0x7ff)<<4;
+ dwOvRCr = (((INT32)(OvRCr * 256.0))&0x7ff)<<20;
+ dwOvGCb = (((INT32)(OvGCb * 256.0))&0x7ff)<<4;
+ dwOvGCr = (((INT32)(OvGCr * 256.0))&0x7ff)<<20;
+ dwOvBCb = (((INT32)(OvBCb * 256.0))&0x7ff)<<4;
+ dwOvBCr = (((INT32)(OvBCr * 256.0))&0x7ff)<<20;
+ }
+ OUTREG(RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvLuma);
+ OUTREG(RADEON_OV0_LIN_TRANS_B, dwOvROff | dwOvRCr);
+ OUTREG(RADEON_OV0_LIN_TRANS_C, dwOvGCb | dwOvLuma);
+ OUTREG(RADEON_OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr);
+ OUTREG(RADEON_OV0_LIN_TRANS_E, dwOvBCb | dwOvLuma);
+ OUTREG(RADEON_OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr);
+}
+
+static void RADEONSetColorKey(ScrnInfoPtr pScrn, CARD32 colorKey)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ CARD32 min, max;
+ CARD8 r, g, b;
+
+ if (info->CurrentLayout.depth > 8)
+ {
+ CARD32 rbits, gbits, bbits;
+
+ rbits = (colorKey & pScrn->mask.red) >> pScrn->offset.red;
+ gbits = (colorKey & pScrn->mask.green) >> pScrn->offset.green;
+ bbits = (colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
+
+ r = rbits << (8 - pScrn->weight.red);
+ g = gbits << (8 - pScrn->weight.green);
+ b = bbits << (8 - pScrn->weight.blue);
+ }
+ else
+ {
+ CARD32 bits;
+
+ bits = colorKey & ((1 << info->CurrentLayout.depth) - 1);
+ r = bits;
+ g = bits;
+ b = bits;
+ }
+ min = (r << 16) | (g << 8) | (b);
+ max = (0xff << 24) | (r << 16) | (g << 8) | (b);
+
+ RADEONWaitForFifo(pScrn, 2);
+ OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max);
+ OUTREG(RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min);
+}
+
+static void
+RADEONResetVideo(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
+
+ if (info->accelOn) info->accel->Sync(pScrn);
+
+ RADEONWaitForIdleMMIO(pScrn);
+ OUTREG(RADEON_OV0_SCALE_CNTL, 0x80000000);
+ OUTREG(RADEON_OV0_AUTO_FLIP_CNTL, 0); /* maybe */
+ OUTREG(RADEON_OV0_EXCLUSIVE_HORZ, 0);
+ OUTREG(RADEON_OV0_FILTER_CNTL, 0x0000000f);
+ OUTREG(RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ |
+ RADEON_VIDEO_KEY_FN_FALSE |
+ RADEON_CMP_MIX_OR);
+ OUTREG(RADEON_OV0_TEST, 0);
+ OUTREG(RADEON_FCP_CNTL, RADEON_FCP0_SRC_GND);
+ OUTREG(RADEON_CAP0_TRIG_CNTL, 0);
+ RADEONSetColorKey(pScrn, pPriv->colorKey);
+
+ if (info->ChipFamily == CHIP_FAMILY_R200 ||
+ info->ChipFamily == CHIP_FAMILY_R300) {
+ int i;
+
+ OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a20000);
+ OUTREG(RADEON_OV0_LIN_TRANS_B, 0x198a190e);
+ OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a2f9da);
+ OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf2fe0442);
+ OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a22046);
+ OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f);
+
+ /*
+ * Set default Gamma ramp:
+ *
+ * Of 18 segments for gamma curve, all segments in R200 (and
+ * newer) are programmable, while only lower 4 and upper 2
+ * segments are programmable in the older Radeons.
+ */
+ for (i = 0; i < 18; i++) {
+ OUTREG(def_gamma[i].gammaReg,
+ (def_gamma[i].gammaSlope<<16) | def_gamma[i].gammaOffset);
+ }
+ } else {
+ OUTREG(RADEON_OV0_LIN_TRANS_A, 0x12a00000);
+ OUTREG(RADEON_OV0_LIN_TRANS_B, 0x1990190e);
+ OUTREG(RADEON_OV0_LIN_TRANS_C, 0x12a0f9c0);
+ OUTREG(RADEON_OV0_LIN_TRANS_D, 0xf3000442);
+ OUTREG(RADEON_OV0_LIN_TRANS_E, 0x12a02040);
+ OUTREG(RADEON_OV0_LIN_TRANS_F, 0x175f);
+ }
+}
+
+
+static XF86VideoAdaptorPtr
+RADEONAllocAdaptor(ScrnInfoPtr pScrn)
+{
+ XF86VideoAdaptorPtr adapt;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr pPriv;
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
+ return NULL;
+
+ if(!(pPriv = xcalloc(1, sizeof(RADEONPortPrivRec) + sizeof(DevUnion))))
+ {
+ xfree(adapt);
+ return NULL;
+ }
+
+ adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
+ adapt->pPortPrivates[0].ptr = (pointer)pPriv;
+
+ pPriv->colorKey = info->videoKey;
+ pPriv->doubleBuffer = TRUE;
+ pPriv->videoStatus = 0;
+ pPriv->brightness = 0;
+ pPriv->transform_index = 0;
+ pPriv->saturation = 0;
+ pPriv->contrast = 0;
+ pPriv->red_intensity = 0;
+ pPriv->green_intensity = 0;
+ pPriv->blue_intensity = 0;
+ pPriv->hue = 0;
+ pPriv->currentBuffer = 0;
+ pPriv->autopaint_colorkey = TRUE;
+
+ /*
+ * Unlike older Mach64 chips, RADEON has only two ECP settings:
+ * 0 for PIXCLK < 175Mhz, and 1 (divide by 2)
+ * for higher clocks, sure makes life nicer
+ */
+ if(info->ModeReg.dot_clock_freq < 17500)
+ pPriv->ecp_div = 0;
+ else
+ pPriv->ecp_div = 1;
+
+#if 0
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Dotclock is %g Mhz, setting ecp_div to %d\n", info->ModeReg.dot_clock_freq/100.0, pPriv->ecp_div);
+#endif
+
+ OUTPLL(RADEON_VCLK_ECP_CNTL, (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) &
+ 0xfffffCff) | (pPriv->ecp_div << 8));
+
+ info->adaptor = adapt;
+
+ return adapt;
+}
+
+static XF86VideoAdaptorPtr
+RADEONSetupImageVideo(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ RADEONPortPrivPtr pPriv;
+ XF86VideoAdaptorPtr adapt;
+
+ if(!(adapt = RADEONAllocAdaptor(pScrn)))
+ return NULL;
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ adapt->name = "ATI Radeon 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 = RADEONStopVideo;
+ adapt->SetPortAttribute = RADEONSetPortAttribute;
+ adapt->GetPortAttribute = RADEONGetPortAttribute;
+ adapt->QueryBestSize = RADEONQueryBestSize;
+ adapt->PutImage = RADEONPutImage;
+ adapt->QueryImageAttributes = RADEONQueryImageAttributes;
+
+ pPriv = (RADEONPortPrivPtr)(adapt->pPortPrivates[0].ptr);
+ REGION_INIT(pScreen, &(pPriv->clip), NullBox, 0);
+
+ xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+ xvSaturation = MAKE_ATOM("XV_SATURATION");
+ xvColor = MAKE_ATOM("XV_COLOR");
+ xvContrast = MAKE_ATOM("XV_CONTRAST");
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
+ xvHue = MAKE_ATOM("XV_HUE");
+ xvRedIntensity = MAKE_ATOM("XV_RED_INTENSITY");
+ xvGreenIntensity = MAKE_ATOM("XV_GREEN_INTENSITY");
+ xvBlueIntensity = MAKE_ATOM("XV_BLUE_INTENSITY");
+
+ xvAutopaintColorkey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
+ xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS");
+
+ RADEONResetVideo(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;
+}
+
+
+/* RADEONClipVideo -
+
+ 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
+RADEONClipVideo(
+ 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
+RADEONStopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
+
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+
+ if(cleanup) {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ RADEONWaitForFifo(pScrn, 2);
+ OUTREG(RADEON_OV0_SCALE_CNTL, 0);
+ if (info->cursor_start)
+ xf86ForceHWCursor (pScrn->pScreen, FALSE);
+ }
+ if(info->videoLinear) {
+ xf86FreeOffscreenLinear(info->videoLinear);
+ info->videoLinear = NULL;
+ }
+ pPriv->videoStatus = 0;
+ } else {
+ if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ pPriv->videoStatus |= OFF_TIMER;
+ pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+ }
+ }
+}
+
+static int
+RADEONSetPortAttribute(ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value,
+ pointer data)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
+ Bool setTransform = FALSE;
+
+ info->accel->Sync(pScrn);
+
+#define RTFSaturation(a) (1.0 + ((a)*1.0)/1000.0)
+#define RTFBrightness(a) (((a)*1.0)/2000.0)
+#define RTFIntensity(a) (((a)*1.0)/2000.0)
+#define RTFContrast(a) (1.0 + ((a)*1.0)/1000.0)
+#define RTFHue(a) (((a)*3.1416)/1000.0)
+#define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v))
+
+ if(attribute == xvAutopaintColorkey)
+ {
+ pPriv->autopaint_colorkey = ClipValue (value, 0, 1);
+ }
+ else if(attribute == xvSetDefaults)
+ {
+ pPriv->autopaint_colorkey = TRUE;
+ pPriv->brightness = 0;
+ pPriv->saturation = 0;
+ pPriv->contrast = 0;
+ pPriv->hue = 0;
+ pPriv->red_intensity = 0;
+ pPriv->green_intensity = 0;
+ pPriv->blue_intensity = 0;
+ pPriv->doubleBuffer = FALSE;
+ setTransform = TRUE;
+ }
+ else if(attribute == xvBrightness)
+ {
+ pPriv->brightness = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if((attribute == xvSaturation) || (attribute == xvColor))
+ {
+ pPriv->saturation = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvContrast)
+ {
+ pPriv->contrast = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvHue)
+ {
+ pPriv->hue = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvRedIntensity)
+ {
+ pPriv->red_intensity = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvGreenIntensity)
+ {
+ pPriv->green_intensity = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvBlueIntensity)
+ {
+ pPriv->blue_intensity = ClipValue (value, -1000, 1000);
+ setTransform = TRUE;
+ }
+ else if(attribute == xvDoubleBuffer)
+ {
+ pPriv->doubleBuffer = ClipValue (value, 0, 1);
+ pPriv->doubleBuffer = value;
+ }
+ else if(attribute == xvColorKey)
+ {
+ pPriv->colorKey = value;
+ RADEONSetColorKey (pScrn, pPriv->colorKey);
+ REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
+ }
+ else
+ return BadMatch;
+
+ if (setTransform)
+ {
+ RADEONSetTransform(pScrn,
+ RTFBrightness(pPriv->brightness),
+ RTFContrast(pPriv->contrast),
+ RTFSaturation(pPriv->saturation),
+ RTFHue(pPriv->hue),
+ RTFIntensity(pPriv->red_intensity),
+ RTFIntensity(pPriv->green_intensity),
+ RTFIntensity(pPriv->blue_intensity),
+ pPriv->transform_index);
+ }
+
+ return Success;
+}
+
+static int
+RADEONGetPortAttribute(ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value,
+ pointer data)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
+
+ if (info->accelOn) info->accel->Sync(pScrn);
+
+ if(attribute == xvAutopaintColorkey)
+ *value = pPriv->autopaint_colorkey;
+ else if(attribute == xvBrightness)
+ *value = pPriv->brightness;
+ else if((attribute == xvSaturation) || (attribute == xvColor))
+ *value = pPriv->saturation;
+ else if(attribute == xvContrast)
+ *value = pPriv->contrast;
+ else if(attribute == xvHue)
+ *value = pPriv->hue;
+ else if(attribute == xvRedIntensity)
+ *value = pPriv->red_intensity;
+ else if(attribute == xvGreenIntensity)
+ *value = pPriv->green_intensity;
+ else if(attribute == xvBlueIntensity)
+ *value = pPriv->blue_intensity;
+ else if(attribute == xvDoubleBuffer)
+ *value = pPriv->doubleBuffer ? 1 : 0;
+ else if(attribute == xvColorKey)
+ *value = pPriv->colorKey;
+ else
+ return BadMatch;
+
+ return Success;
+}
+
+static void
+RADEONQueryBestSize(
+ 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;
+}
+
+static void
+RADEONCopyData(
+ 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
+RADEONCopyMungedData(
+ 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 = (pointer)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
+RADEONAllocateMemory(
+ 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
+RADEONDisplayVideo(
+ ScrnInfoPtr pScrn,
+ int id,
+ int offset1, int offset2,
+ 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
+){
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ int v_inc, h_inc, step_by, tmp;
+ int p1_h_accum_init, p23_h_accum_init;
+ int p1_v_accum_init;
+ int ecp_div;
+ int v_inc_shift;
+ int y_mult;
+ int x_off;
+ CARD32 scaler_src;
+
+ /* Unlike older Mach64 chips, RADEON has only two ECP settings: 0 for PIXCLK < 175Mhz, and 1 (divide by 2)
+ for higher clocks, sure makes life nicer
+
+ Here we need to find ecp_div again, as the user may have switched resolutions */
+ if(info->ModeReg.dot_clock_freq < 17500)
+ ecp_div = 0;
+ else
+ ecp_div = 1;
+
+ OUTPLL(RADEON_VCLK_ECP_CNTL, (INPLL(pScrn, RADEON_VCLK_ECP_CNTL) & 0xfffffCff) | (ecp_div << 8));
+
+ v_inc_shift = 20;
+ if (pScrn->currentMode->Flags & V_INTERLACE)
+ v_inc_shift++;
+ if (pScrn->currentMode->Flags & V_DBLSCAN)
+ v_inc_shift--;
+ v_inc = (src_h << v_inc_shift) / drw_h;
+ h_inc = ((src_w << (12 + ecp_div)) / drw_w);
+ step_by = 1;
+
+ while(h_inc >= (2 << 12)) {
+ step_by++;
+ h_inc >>= 1;
+ }
+
+ /* keep everything in 16.16 */
+
+ offset1 += ((left >> 16) & ~7) << 1;
+ offset2 += ((left >> 16) & ~7) << 1;
+
+ if (info->IsSecondary) {
+ offset1 += info->FbMapSize;
+ offset2 += info->FbMapSize;
+ }
+
+ 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;
+
+ RADEONWaitForFifo(pScrn, 2);
+ OUTREG(RADEON_OV0_REG_LOAD_CNTL, 1);
+ if (info->accelOn) info->accel->Sync(pScrn);
+ while(!(INREG(RADEON_OV0_REG_LOAD_CNTL) & (1 << 3)));
+
+ RADEONWaitForFifo(pScrn, 14);
+ OUTREG(RADEON_OV0_H_INC, h_inc | ((h_inc >> 1) << 16));
+ OUTREG(RADEON_OV0_STEP_BY, step_by | (step_by << 8));
+
+ y_mult = 1;
+ if (pScrn->currentMode->Flags & V_DBLSCAN)
+ y_mult = 2;
+ x_off = 8;
+ if (info->ChipFamily == CHIP_FAMILY_R200 ||
+ info->ChipFamily == CHIP_FAMILY_R300)
+ x_off = 0;
+
+ /* Put the hardware overlay on CRTC2:
+ *
+ * Since one hardware overlay can not be displayed on two heads
+ * at the same time, we might need to consider using software
+ * rendering for the second head.
+ */
+ if ((info->Clone && info->OverlayOnCRTC2) || info->IsSecondary) {
+ x_off = 0;
+ OUTREG(RADEON_OV1_Y_X_START, ((dstBox->x1
+ + x_off
+ - info->CloneFrameX0
+ + pScrn->frameX0) |
+ ((dstBox->y1*y_mult -
+ info->CloneFrameY0
+ + pScrn->frameY0) << 16)));
+ OUTREG(RADEON_OV1_Y_X_END, ((dstBox->x2
+ + x_off
+ - info->CloneFrameX0
+ + pScrn->frameX0) |
+ ((dstBox->y2*y_mult
+ - info->CloneFrameY0
+ + pScrn->frameY0) << 16)));
+ scaler_src = (1 << 14);
+ } else {
+ OUTREG(RADEON_OV0_Y_X_START, ((dstBox->x1 + x_off) |
+ ((dstBox->y1*y_mult) << 16)));
+ OUTREG(RADEON_OV0_Y_X_END, ((dstBox->x2 + x_off) |
+ ((dstBox->y2*y_mult) << 16)));
+ scaler_src = 0;
+ }
+
+ OUTREG(RADEON_OV0_V_INC, v_inc);
+ OUTREG(RADEON_OV0_P1_BLANK_LINES_AT_TOP, 0x00000fff | ((src_h - 1) << 16));
+ OUTREG(RADEON_OV0_VID_BUF_PITCH0_VALUE, pitch);
+ OUTREG(RADEON_OV0_VID_BUF_PITCH1_VALUE, pitch);
+ OUTREG(RADEON_OV0_P1_X_START_END, (src_w + left - 1) | (left << 16));
+ left >>= 1; src_w >>= 1;
+ OUTREG(RADEON_OV0_P2_X_START_END, (src_w + left - 1) | (left << 16));
+ OUTREG(RADEON_OV0_P3_X_START_END, (src_w + left - 1) | (left << 16));
+ OUTREG(RADEON_OV0_VID_BUF0_BASE_ADRS, offset1 & 0xfffffff0);
+ OUTREG(RADEON_OV0_VID_BUF1_BASE_ADRS, offset2 & 0xfffffff0);
+ OUTREG(RADEON_OV0_VID_BUF2_BASE_ADRS, offset1 & 0xfffffff0);
+
+ RADEONWaitForFifo(pScrn, 9);
+ OUTREG(RADEON_OV0_VID_BUF3_BASE_ADRS, offset2 & 0xfffffff0);
+ OUTREG(RADEON_OV0_VID_BUF4_BASE_ADRS, offset1 & 0xfffffff0);
+ OUTREG(RADEON_OV0_VID_BUF5_BASE_ADRS, offset2 & 0xfffffff0);
+ OUTREG(RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
+ OUTREG(RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
+ OUTREG(RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
+
+#if 0
+ if(id == FOURCC_UYVY)
+ OUTREG(RADEON_OV0_SCALE_CNTL, 0x41008C03);
+ else
+ OUTREG(RADEON_OV0_SCALE_CNTL, 0x41008B03);
+#endif
+
+ if (id == FOURCC_UYVY)
+ OUTREG(RADEON_OV0_SCALE_CNTL, (RADEON_SCALER_SOURCE_YVYU422
+ | RADEON_SCALER_ADAPTIVE_DEINT
+ | RADEON_SCALER_SMART_SWITCH
+ | RADEON_SCALER_DOUBLE_BUFFER
+ | RADEON_SCALER_ENABLE
+ | scaler_src));
+ else
+ OUTREG(RADEON_OV0_SCALE_CNTL, (RADEON_SCALER_SOURCE_VYUY422
+ | RADEON_SCALER_ADAPTIVE_DEINT
+ | RADEON_SCALER_SMART_SWITCH
+ | RADEON_SCALER_DOUBLE_BUFFER
+ | RADEON_SCALER_ENABLE
+ | scaler_src));
+
+ OUTREG(RADEON_OV0_REG_LOAD_CNTL, 0);
+}
+
+
+static int
+RADEONPutImage(
+ 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
+){
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
+ INT32 xa, xb, ya, yb;
+ unsigned char *dst_start;
+ int pitch, new_size, offset, s2offset, s3offset;
+ int srcPitch, srcPitch2, dstPitch;
+ int top, left, npixels, nlines, bpp;
+ BoxRec dstBox;
+ CARD32 tmp;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ unsigned char *RADEONMMIO = info->MMIO;
+ CARD32 surface_cntl = INREG(RADEON_SURFACE_CNTL);
+
+ OUTREG(RADEON_SURFACE_CNTL, (surface_cntl |
+ RADEON_NONSURF_AP0_SWP_32BPP) & ~RADEON_NONSURF_AP0_SWP_16BPP);
+#endif
+
+ /*
+ * 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.
+ *
+ */
+
+ /* make the compiler happy */
+ s2offset = s3offset = srcPitch2 = 0;
+
+ 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(!RADEONClipVideo(&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:
+ dstPitch = ((width << 1) + 15) & ~15;
+ new_size = ((dstPitch * height) + bpp - 1) / bpp;
+ srcPitch = (width + 3) & ~3;
+ s2offset = srcPitch * height;
+ srcPitch2 = ((width >> 1) + 3) & ~3;
+ s3offset = (srcPitch2 * (height >> 1)) + s2offset;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ default:
+ dstPitch = ((width << 1) + 15) & ~15;
+ new_size = ((dstPitch * height) + bpp - 1) / bpp;
+ srcPitch = (width << 1);
+ break;
+ }
+
+ if(!(info->videoLinear = RADEONAllocateMemory(pScrn, info->videoLinear,
+ 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 = (info->videoLinear->offset * bpp) + (top * dstPitch);
+ if(pPriv->doubleBuffer)
+ offset += pPriv->currentBuffer * new_size * bpp;
+
+ dst_start = info->FB + offset;
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ top &= ~1;
+ dst_start += left << 1;
+ 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;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ OUTREG(RADEON_SURFACE_CNTL, (surface_cntl | RADEON_NONSURF_AP0_SWP_32BPP)
+ & ~RADEON_NONSURF_AP0_SWP_16BPP);
+#endif
+ RADEONCopyMungedData(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;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ OUTREG(RADEON_SURFACE_CNTL, surface_cntl & ~(RADEON_NONSURF_AP0_SWP_32BPP
+ | RADEON_NONSURF_AP0_SWP_16BPP));
+#endif
+ RADEONCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
+ break;
+ }
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ /* restore byte swapping */
+ OUTREG(RADEON_SURFACE_CNTL, surface_cntl);
+#endif
+
+ /* update cliplist */
+ if(!RegionsEqual(&pPriv->clip, clipBoxes))
+ {
+ REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
+ /* draw these */
+ if(pPriv->autopaint_colorkey)
+ (*info->accel->FillSolidRects)(pScrn, pPriv->colorKey, GXcopy,
+ (CARD32)~0,
+ REGION_NUM_RECTS(clipBoxes),
+ REGION_RECTS(clipBoxes));
+ }
+
+ if (info->cursor_start && !(pPriv->videoStatus & CLIENT_VIDEO_ON))
+ xf86ForceHWCursor (pScrn->pScreen, TRUE);
+
+ RADEONDisplayVideo(pScrn, id, offset, offset, width, height, dstPitch,
+ xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+
+ info->VideoTimerCallback = RADEONVideoTimerCallback;
+
+ return Success;
+}
+
+
+static int
+RADEONQueryImageAttributes(
+ ScrnInfoPtr pScrn,
+ int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets
+){
+ int size, tmp;
+
+ if(*w > 2048) *w = 2048;
+ if(*h > 2048) *h = 2048;
+
+ *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
+RADEONVideoTimerCallback(ScrnInfoPtr pScrn, Time now)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr pPriv = info->adaptor->pPortPrivates[0].ptr;
+
+ if(pPriv->videoStatus & TIMER_MASK) {
+ if(pPriv->videoStatus & OFF_TIMER) {
+ if(pPriv->offTime < now) {
+ unsigned char *RADEONMMIO = info->MMIO;
+ OUTREG(RADEON_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(info->videoLinear) {
+ xf86FreeOffscreenLinear(info->videoLinear);
+ info->videoLinear = 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;
+}
+
+/****************** Offscreen stuff ***************/
+typedef struct {
+ FBLinearPtr linear;
+ Bool isOn;
+} OffscreenPrivRec, * OffscreenPrivPtr;
+
+static int
+RADEONAllocateSurface(
+ 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 = RADEONAllocateMemory(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
+RADEONStopSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+ RADEONInfoPtr info = RADEONPTR(surface->pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+
+ if(pPriv->isOn) {
+ OUTREG(RADEON_OV0_SCALE_CNTL, 0);
+ pPriv->isOn = FALSE;
+ }
+ return Success;
+}
+
+
+static int
+RADEONFreeSurface(
+ XF86SurfacePtr surface
+){
+ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
+
+ if(pPriv->isOn)
+ RADEONStopSurface(surface);
+ xf86FreeOffscreenLinear(pPriv->linear);
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ xfree(surface->devPrivate.ptr);
+
+ return Success;
+}
+
+static int
+RADEONGetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 *value
+){
+ return RADEONGetPortAttribute(pScrn, attribute, value,
+ (pointer)(GET_PORT_PRIVATE(pScrn)));
+}
+
+static int
+RADEONSetSurfaceAttribute(
+ ScrnInfoPtr pScrn,
+ Atom attribute,
+ INT32 value
+){
+ return RADEONSetPortAttribute(pScrn, attribute, value,
+ (pointer)(GET_PORT_PRIVATE(pScrn)));
+}
+
+
+static int
+RADEONDisplaySurface(
+ 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;
+
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPortPrivPtr portPriv = info->adaptor->pPortPrivates[0].ptr;
+
+ INT32 xa, ya, xb, yb;
+ BoxRec dstBox;
+
+ if (src_w > (drw_w << 4))
+ drw_w = src_w >> 4;
+ if (src_h > (drw_h << 4))
+ drw_h = src_h >> 4;
+
+ 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 (!RADEONClipVideo(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
+ surface->width, surface->height))
+ return Success;
+
+ dstBox.x1 -= pScrn->frameX0;
+ dstBox.x2 -= pScrn->frameX0;
+ dstBox.y1 -= pScrn->frameY0;
+ dstBox.y2 -= pScrn->frameY0;
+
+ RADEONResetVideo(pScrn);
+
+ RADEONDisplayVideo(pScrn, surface->id,
+ surface->offsets[0], surface->offsets[0],
+ surface->width, surface->height, surface->pitches[0],
+ xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
+
+ if (portPriv->autopaint_colorkey)
+ (*info->accel->FillSolidRects)(pScrn, portPriv->colorKey, GXcopy,
+ (CARD32)~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();
+ if (info->cursor_start)
+ xf86ForceHWCursor (pScrn->pScreen, FALSE);
+ portPriv->videoStatus = FREE_TIMER;
+ portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ info->VideoTimerCallback = RADEONVideoTimerCallback;
+ }
+
+ return Success;
+}
+
+
+static void
+RADEONInitOffscreenImages(ScreenPtr pScreen)
+{
+/* ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ RADEONInfoPtr info = RADEONPTR(pScrn); */
+ 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 = RADEONAllocateSurface;
+ offscreenImages[0].free_surface = RADEONFreeSurface;
+ offscreenImages[0].display = RADEONDisplaySurface;
+ offscreenImages[0].stop = RADEONStopSurface;
+ offscreenImages[0].setAttribute = RADEONSetSurfaceAttribute;
+ offscreenImages[0].getAttribute = RADEONGetSurfaceAttribute;
+ offscreenImages[0].max_width = 1024;
+ offscreenImages[0].max_height = 1024;
+ offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
+ offscreenImages[0].attributes = Attributes;
+
+ xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
+}
+
+#endif /* !XvExtension */