xenocara/driver/xf86-video-mga/src/mga_video.c
2012-09-08 16:35:55 +00:00

2032 lines
54 KiB
C

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "xf86_OSproc.h"
#include "compiler.h"
#include "xf86Pci.h"
#include "xf86fbman.h"
#include "regionstr.h"
#include "mga_reg.h"
#include "mga.h"
#include "mga_macros.h"
#include "xf86xv.h"
#include <X11/extensions/Xv.h>
#ifdef USE_XAA
#include "xaa.h"
#include "xaalocal.h"
#endif
#include "dixstruct.h"
#include "fourcc.h"
#define OFF_DELAY 250 /* milliseconds */
#define FREE_DELAY 15000
#define OFF_TIMER 0x01
#define FREE_TIMER 0x02
#define CLIENT_VIDEO_ON 0x04
#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
#define MGA_MAX_PORTS 32
static void MGAInitOffscreenImages(ScreenPtr);
static XF86VideoAdaptorPtr MGASetupImageVideoOverlay(ScreenPtr);
static int MGASetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
static int MGAGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
static XF86VideoAdaptorPtr MGASetupImageVideoTexture(ScreenPtr);
static int MGASetPortAttributeTexture(ScrnInfoPtr, Atom, INT32, pointer);
static int MGAGetPortAttributeTexture(ScrnInfoPtr, Atom ,INT32 *, pointer);
static void MGAStopVideo(ScrnInfoPtr, pointer, Bool);
static void MGAQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
unsigned int *, unsigned int *, pointer);
static int MGAPutImage(ScrnInfoPtr, short, short, short, short, short,
short, short, short, int, unsigned char*, short,
short, Bool, RegionPtr, pointer, DrawablePtr);
static int MGAQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
unsigned short *, int *, int *);
static void MGAFreeMemory(ScrnInfoPtr pScrn, void *mem_struct);
static void MGAResetVideoOverlay(ScrnInfoPtr);
static void MGAVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
static XF86VideoAdaptorPtr MGASetupImageVideoILOAD(ScreenPtr);
static int MGAPutImageILOAD(ScrnInfoPtr, short, short, short, short, short,
short, short, short, int, unsigned char*, short,
short, Bool, RegionPtr, pointer, DrawablePtr);
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
static Atom xvBrightness, xvContrast, xvColorKey, xvDoubleBuffer;
#ifdef USE_EXA
static void
MGAVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
if (pPriv->video_memory == area)
pPriv->video_memory = NULL;
}
#endif /* USE_EXA */
void MGAInitVideo(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
XF86VideoAdaptorPtr newAdaptor = NULL;
MGAPtr pMga = MGAPTR(pScrn);
int num_adaptors;
if ((pScrn->bitsPerPixel != 8) && !pMga->NoAccel &&
(pMga->SecondCrtc == FALSE) &&
((pMga->Chipset == PCI_CHIP_MGA2164) ||
(pMga->Chipset == PCI_CHIP_MGA2164_AGP) ||
/* (pMga->Chipset == PCI_CHIP_MGA2064) || */
(pMga->Chipset == PCI_CHIP_MGAG200) ||
(pMga->Chipset == PCI_CHIP_MGAG200_PCI) ||
(pMga->Chipset == PCI_CHIP_MGAG400) ||
(pMga->Chipset == PCI_CHIP_MGAG550))) {
if ((pMga->Chipset == PCI_CHIP_MGA2164) ||
/* (pMga->Chipset == PCI_CHIP_MGA2064) || */
(pMga->Chipset == PCI_CHIP_MGA2164_AGP)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using MGA 2164W ILOAD video\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"This is an experimental driver and may not work on your machine.\n");
newAdaptor = MGASetupImageVideoILOAD(pScreen);
pMga->TexturedVideo = TRUE;
/* ^^^ this is not really true but the ILOAD scaler shares
* much more code with the textured video than the overlay
*/
} else if (pMga->TexturedVideo && (pScrn->bitsPerPixel != 24)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using texture video\n");
newAdaptor = MGASetupImageVideoTexture(pScreen);
pMga->TexturedVideo = TRUE;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
newAdaptor = MGASetupImageVideoOverlay(pScreen);
pMga->TexturedVideo = FALSE;
}
MGAInitOffscreenImages(pScreen);
}
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
if(newAdaptor) {
if(!num_adaptors) {
num_adaptors = 1;
adaptors = &newAdaptor;
} else {
/* need to free this someplace */
newAdaptors = malloc((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);
free(newAdaptors);
}
/* client libraries expect an encoding */
static XF86VideoEncodingRec DummyEncoding[2] =
{
{ /* overlay limit */
0,
"XV_IMAGE",
1024, 1024,
{1, 1}
},
{ /* texture limit */
0,
"XV_IMAGE",
2046, 2046,
{1, 1}
}
};
#define NUM_FORMATS 6
static XF86VideoFormatRec Formats[NUM_FORMATS] =
{
{15, TrueColor}, {16, TrueColor}, {24, TrueColor},
{15, DirectColor}, {16, DirectColor}, {24, DirectColor}
};
#define NUM_ATTRIBUTES_OVERLAY 4
static XF86AttributeRec Attributes[NUM_ATTRIBUTES_OVERLAY] =
{
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
{XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
};
#define NUM_IMAGES 4
static XF86ImageRec Images[NUM_IMAGES] =
{
XVIMAGE_YUY2,
XVIMAGE_YV12,
XVIMAGE_I420,
XVIMAGE_UYVY
};
static void
MGAResetVideoOverlay(ScrnInfoPtr pScrn)
{
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
CHECK_DMA_QUIESCENT(pMga, pScrn);
outMGAdac(0x51, 0x01); /* keying on */
outMGAdac(0x52, 0xff); /* full mask */
outMGAdac(0x53, 0xff);
outMGAdac(0x54, 0xff);
outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
pScrn->offset.red);
outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
pScrn->offset.green);
outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
pScrn->offset.blue);
OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
(pPriv->contrast & 0xff));
}
static XF86VideoAdaptorPtr
MGAAllocAdaptor(ScrnInfoPtr pScrn, Bool doublebuffer)
{
XF86VideoAdaptorPtr adapt;
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv;
int i;
if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
return NULL;
if(!(pPriv = calloc(1, sizeof(MGAPortPrivRec) +
(sizeof(DevUnion) * MGA_MAX_PORTS))))
{
free(adapt);
return NULL;
}
adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
for(i = 0; i < MGA_MAX_PORTS; i++)
adapt->pPortPrivates[i].val = i;
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
xvColorKey = MAKE_ATOM("XV_COLORKEY");
xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
pPriv->colorKey = pMga->videoKey;
pPriv->videoStatus = 0;
pPriv->brightness = 0;
pPriv->contrast = 128;
pPriv->lastPort = -1;
pPriv->doubleBuffer = doublebuffer;
pPriv->currentBuffer = 0;
pMga->adaptor = adapt;
pMga->portPrivate = pPriv;
return adapt;
}
static XF86VideoAdaptorPtr
MGASetupImageVideoOverlay(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
MGAPtr pMga = MGAPTR(pScrn);
XF86VideoAdaptorPtr adapt;
adapt = MGAAllocAdaptor(pScrn, TRUE);
if (adapt == NULL)
return NULL;
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
adapt->name = "Matrox G-Series Backend Scaler";
adapt->nEncodings = 1;
adapt->pEncodings = &DummyEncoding[0];
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = Formats;
adapt->nPorts = 1;
adapt->pAttributes = Attributes;
if (pMga->Chipset == PCI_CHIP_MGAG400 ||
pMga->Chipset == PCI_CHIP_MGAG550) {
adapt->nImages = 4;
adapt->nAttributes = 4;
} else {
adapt->nImages = 3;
adapt->nAttributes = 1;
}
adapt->pImages = Images;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = MGAStopVideo;
adapt->SetPortAttribute = MGASetPortAttributeOverlay;
adapt->GetPortAttribute = MGAGetPortAttributeOverlay;
adapt->QueryBestSize = MGAQueryBestSize;
adapt->PutImage = MGAPutImage;
adapt->QueryImageAttributes = MGAQueryImageAttributes;
/* gotta uninit this someplace */
REGION_NULL(pScreen, &(pMga->portPrivate->clip));
MGAResetVideoOverlay(pScrn);
return adapt;
}
static XF86VideoAdaptorPtr
MGASetupImageVideoTexture(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
XF86VideoAdaptorPtr adapt;
MGAPtr pMga = MGAPTR(pScrn);
adapt = MGAAllocAdaptor(pScrn, FALSE);
if (adapt == NULL)
return NULL;
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = 0;
adapt->name = "Matrox G-Series Texture Engine";
adapt->nEncodings = 1;
adapt->pEncodings = &DummyEncoding[1];
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = Formats;
adapt->nPorts = MGA_MAX_PORTS;
adapt->pAttributes = NULL;
adapt->nAttributes = 0;
adapt->pImages = Images;
if (pMga->Chipset == PCI_CHIP_MGAG400 ||
pMga->Chipset == PCI_CHIP_MGAG550)
adapt->nImages = 4;
else
adapt->nImages = 3;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = MGAStopVideo;
adapt->SetPortAttribute = MGASetPortAttributeTexture;
adapt->GetPortAttribute = MGAGetPortAttributeTexture;
adapt->QueryBestSize = MGAQueryBestSize;
adapt->PutImage = MGAPutImage;
adapt->QueryImageAttributes = MGAQueryImageAttributes;
return adapt;
}
static void
MGAStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
{
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
if(pMga->TexturedVideo) return;
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
if(shutdown) {
if(pPriv->videoStatus & CLIENT_VIDEO_ON)
OUTREG(MGAREG_BESCTL, 0);
if (pPriv->video_memory) {
MGAFreeMemory(pScrn, pPriv->video_memory);
pPriv->video_memory = NULL;
}
pPriv->videoStatus = 0;
} else {
if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
pPriv->videoStatus |= OFF_TIMER;
pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
}
}
}
static int
MGASetPortAttributeOverlay(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 value,
pointer data
){
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
CHECK_DMA_QUIESCENT(pMga, pScrn);
if(attribute == xvBrightness) {
if((value < -128) || (value > 127))
return BadValue;
pPriv->brightness = value;
OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
(pPriv->contrast & 0xff));
} else
if(attribute == xvContrast) {
if((value < 0) || (value > 255))
return BadValue;
pPriv->contrast = value;
OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
(pPriv->contrast & 0xff));
} else
if(attribute == xvColorKey) {
pPriv->colorKey = value;
outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
pScrn->offset.red);
outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
pScrn->offset.green);
outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
pScrn->offset.blue);
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
} else
if(attribute == xvDoubleBuffer) {
if((value < 0) || (value > 1))
return BadValue;
pPriv->doubleBuffer = value;
} else return BadMatch;
return Success;
}
static int
MGAGetPortAttributeOverlay(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 *value,
pointer data
){
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
if(attribute == xvBrightness) {
*value = pPriv->brightness;
} else
if(attribute == xvContrast) {
*value = pPriv->contrast;
} else
if(attribute == xvDoubleBuffer) {
*value = pPriv->doubleBuffer ? 1 : 0;
} else
if(attribute == xvColorKey) {
*value = pPriv->colorKey;
} else return BadMatch;
return Success;
}
static int
MGASetPortAttributeTexture(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 value,
pointer data
) {
return BadMatch;
}
static int
MGAGetPortAttributeTexture(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 *value,
pointer data
){
return BadMatch;
}
static void
MGAQueryBestSize(
ScrnInfoPtr pScrn,
Bool motion,
short vid_w, short vid_h,
short drw_w, short drw_h,
unsigned int *p_w, unsigned int *p_h,
pointer data
){
*p_w = drw_w;
*p_h = drw_h;
}
static void
MGACopyData(
unsigned char *src,
unsigned char *dst,
int srcPitch,
int dstPitch,
int h,
int w
){
w <<= 1;
while(h--) {
/* XXX Maybe this one needs big-endian fixes, too? -ReneR */
memcpy(dst, src, w);
src += srcPitch;
dst += dstPitch;
}
}
static void
MGACopyMungedData(
unsigned char *src1,
unsigned char *src2,
unsigned char *src3,
unsigned char *dst1,
int srcPitch,
int srcPitch2,
int dstPitch,
int h,
int w
){
CARD32 *dst;
CARD8 *s1, *s2, *s3;
int i, j;
w >>= 1;
for(j = 0; j < h; j++) {
dst = (CARD32*)dst1;
s1 = src1; s2 = src2; s3 = src3;
i = w;
while(i > 4) {
#if X_BYTE_ORDER == X_LITTLE_ENDIAN
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);
#else
dst[0] = (s1[0] << 16) | s1[1] | (s3[0] << 24) | (s2[0] << 8);
dst[1] = (s1[2] << 16) | s1[3] | (s3[1] << 24) | (s2[1] << 8);
dst[2] = (s1[4] << 16) | s1[5] | (s3[2] << 24) | (s2[2] << 8);
dst[3] = (s1[6] << 16) | s1[7] | (s3[3] << 24) | (s2[3] << 8);
#endif
dst += 4; s2 += 4; s3 += 4; s1 += 8;
i -= 4;
}
while(i--) {
#if X_BYTE_ORDER == X_LITTLE_ENDIAN
dst[0] = s1[0] | (s1[1] << 16) | (s3[0] << 8) | (s2[0] << 24);
#else
dst[0] = (s1[0] << 16) | s1[1] | (s3[0] << 24) | (s2[0] << 8);
#endif
dst++; s2++; s3++;
s1 += 2;
}
dst1 += dstPitch;
src1 += srcPitch;
if(j & 1) {
src2 += srcPitch2;
src3 += srcPitch2;
}
}
}
static CARD32
MGAAllocateMemory(
ScrnInfoPtr pScrn,
void **mem_struct,
int size
){
MGAPtr pMga = MGAPTR(pScrn);
ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
int offset = 0;
#ifdef USE_EXA
if (pMga->Exa) {
ExaOffscreenArea *area = *mem_struct;
if (area) {
if (area->size >= size)
return area->offset;
exaOffscreenFree(pScrn->pScreen, area);
}
area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, MGAVideoSave,
NULL);
*mem_struct = area;
if (!area)
return 0;
offset = area->offset;
}
#endif /* USE_EXA */
#ifdef USE_XAA
FBLinearPtr linear = *mem_struct;
int cpp = pMga->CurrentLayout.bitsPerPixel / 8;
/* XAA allocates in units of pixels at the screen bpp, so adjust size
* appropriately.
*/
size = (size + cpp - 1) / cpp;
if (!pMga->Exa) {
if (linear) {
if (linear->size >= size)
return linear->offset * cpp;
if (xf86ResizeOffscreenLinear(linear, size))
return linear->offset * cpp;
xf86FreeOffscreenLinear(linear);
}
linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
NULL, NULL, NULL);
*mem_struct = linear;
if (!linear) {
int max_size;
xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
PRIORITY_EXTREME);
if (max_size < size)
return 0;
xf86PurgeUnlockedOffscreenAreas(pScreen);
linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
NULL, NULL, NULL);
*mem_struct = linear;
if (!linear)
return 0;
}
offset = linear->offset * cpp;
}
#endif /* USE_XAA */
return offset;
}
static void
MGAFreeMemory(ScrnInfoPtr pScrn, void *mem_struct)
{
MGAPtr pMga = MGAPTR(pScrn);
#ifdef USE_EXA
if (pMga->Exa) {
ExaOffscreenArea *area = mem_struct;
if (area)
exaOffscreenFree(pScrn->pScreen, area);
}
#endif /* USE_EXA */
#ifdef USE_XAA
if (!pMga->Exa) {
FBLinearPtr linear = mem_struct;
if (linear)
xf86FreeOffscreenLinear(linear);
}
#endif /* USE_XAA */
}
static void
MGADisplayVideoOverlay(
ScrnInfoPtr pScrn,
int id,
int offset,
short width, short height,
int pitch,
int x1, int y1, int x2, int y2,
BoxPtr dstBox,
short src_w, short src_h,
short drw_w, short drw_h
){
MGAPtr pMga = MGAPTR(pScrn);
int tmp, hzoom, intrep;
int maxOverlayClock;
CHECK_DMA_QUIESCENT(pMga, pScrn);
/* got 48 scanlines to do it in */
tmp = INREG(MGAREG_VCOUNT) + 48;
/* FIXME always change it in vertical retrace use CrtcV ?*/
if(tmp > pScrn->currentMode->CrtcVTotal)
tmp -= 49; /* too bad */
else
tmp = pScrn->currentMode->CrtcVTotal -1;
tmp = pScrn->currentMode->VDisplay +1;
/* enable accelerated 2x horizontal zoom when pixelclock >135MHz */
if ((pMga->ChipRev >= 0x80) || (pMga->Chipset == PCI_CHIP_MGAG550)) {
/* G450, G550 */
maxOverlayClock = 234000;
} else {
maxOverlayClock = 135000;
}
hzoom = (pScrn->currentMode->Clock > maxOverlayClock) ? 1 : 0;
switch(id) {
case FOURCC_UYVY:
OUTREG(MGAREG_BESGLOBCTL, 0x000000c0 | (3 * hzoom) | (tmp << 16));
break;
case FOURCC_YUY2:
default:
OUTREG(MGAREG_BESGLOBCTL, 0x00000080 | (3 * hzoom) | (tmp << 16));
break;
}
OUTREG(MGAREG_BESA1ORG, offset);
if(y1 & 0x00010000)
OUTREG(MGAREG_BESCTL, 0x00040c41);
else
OUTREG(MGAREG_BESCTL, 0x00040c01);
OUTREG(MGAREG_BESHCOORD, (dstBox->x1 << 16) | (dstBox->x2 - 1));
OUTREG(MGAREG_BESVCOORD, (dstBox->y1 << 16) | (dstBox->y2 - 1));
OUTREG(MGAREG_BESHSRCST, x1 & 0x03fffffc);
OUTREG(MGAREG_BESHSRCEND, (x2 - 0x00010000) & 0x03fffffc);
OUTREG(MGAREG_BESHSRCLST, (width - 1) << 16);
OUTREG(MGAREG_BESPITCH, pitch >> 1);
OUTREG(MGAREG_BESV1WGHT, y1 & 0x0000fffc);
OUTREG(MGAREG_BESV1SRCLST, height - 1 - (y1 >> 16));
intrep = ((drw_h == src_h) || (drw_h < 2)) ? 0 : 1;
tmp = ((src_h - intrep) << 16)/(drw_h - intrep);
if(tmp >= (32 << 16))
tmp = (32 << 16) - 1;
OUTREG(MGAREG_BESVISCAL, tmp & 0x001ffffc);
intrep = ((drw_w == src_w) || (drw_w < 2)) ? 0 : 1;
tmp = (((src_w - intrep) << 16)/(drw_w - intrep)) << hzoom;
if(tmp >= (32 << 16))
tmp = (32 << 16) - 1;
OUTREG(MGAREG_BESHISCAL, tmp & 0x001ffffc);
}
/**
* \todo
* Starting with at least the G200, the chip can handle non-mipmapped
* non-power-of-two textures. However, the code in this routine forces the
* texture dimensions to be powers of two. That should simplify the code and
* may improve performance slightly.
*/
static void
MGADisplayVideoTexture(
ScrnInfoPtr pScrn,
int id, int offset,
int nbox, BoxPtr pbox,
int width, int height, int pitch,
short src_x, short src_y,
short src_w, short src_h,
short drw_x, short drw_y,
short drw_w, short drw_h
){
MGAPtr pMga = MGAPTR(pScrn);
int log2w = 0, log2h = 0, i, incx, incy, padw, padh;
pitch >>= 1;
i = 12;
while(--i) {
if(width & (1 << i)) {
log2w = i;
if(width & ((1 << i) - 1))
log2w++;
break;
}
}
i = 12;
while(--i) {
if(height & (1 << i)) {
log2h = i;
if(height & ((1 << i) - 1))
log2h++;
break;
}
}
padw = 1 << log2w;
padh = 1 << log2h;
incx = (src_w << 20)/(drw_w * padw);
incy = (src_h << 20)/(drw_h * padh);
CHECK_DMA_QUIESCENT(pMga, pScrn);
WAITFIFO(15);
OUTREG(MGAREG_TMR0, incx); /* sx inc */
OUTREG(MGAREG_TMR1, 0); /* sy inc */
OUTREG(MGAREG_TMR2, 0); /* tx inc */
OUTREG(MGAREG_TMR3, incy); /* ty inc */
OUTREG(MGAREG_TMR4, 0x00000000);
OUTREG(MGAREG_TMR5, 0x00000000);
OUTREG(MGAREG_TMR8, 0x00010000);
OUTREG(MGAREG_TEXORG, offset);
OUTREG(MGAREG_TEXWIDTH, log2w | (((8 - log2w) & 63) << 9) |
((width - 1) << 18));
OUTREG(MGAREG_TEXHEIGHT, log2h | (((8 - log2h) & 63) << 9) |
((height - 1) << 18));
if(id == FOURCC_UYVY)
OUTREG(MGAREG_TEXCTL, 0x1A00010b | ((pitch & 0x07FF) << 9));
else
OUTREG(MGAREG_TEXCTL, 0x1A00010a | ((pitch & 0x07FF) << 9));
OUTREG(MGAREG_TEXCTL2, 0x00000014);
OUTREG(MGAREG_DWGCTL, 0x000c7076);
OUTREG(MGAREG_TEXFILTER, 0x01e00020);
OUTREG(MGAREG_ALPHACTRL, 0x00000001);
padw = (src_x << 20)/padw;
padh = (src_y << 20)/padh;
while(nbox--) {
WAITFIFO(4);
OUTREG(MGAREG_TMR6, (incx * (pbox->x1 - drw_x)) + padw);
OUTREG(MGAREG_TMR7, (incy * (pbox->y1 - drw_y)) + padh);
OUTREG(MGAREG_FXBNDRY, (pbox->x2 << 16) | (pbox->x1 & 0xffff));
OUTREG(MGAREG_YDSTLEN + MGAREG_EXEC,
(pbox->y1 << 16) | (pbox->y2 - pbox->y1));
pbox++;
}
MGA_MARK_SYNC(pMga, pScrn);
}
static int
MGAPutImage(
ScrnInfoPtr pScrn,
short src_x, short src_y,
short drw_x, short drw_y,
short src_w, short src_h,
short drw_w, short drw_h,
int id, unsigned char* buf,
short width, short height,
Bool Sync,
RegionPtr clipBoxes, pointer data,
DrawablePtr pDraw
){
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
INT32 x1, x2, y1, y2;
unsigned char *dst_start;
int new_size, offset, offset2 = 0, offset3 = 0;
int srcPitch, srcPitch2 = 0, dstPitch;
int top, left, npixels, nlines;
BoxRec dstBox;
CARD32 tmp;
/* Clip */
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
clipBoxes, width, height))
return Success;
if(!pMga->TexturedVideo) {
dstBox.x1 -= pScrn->frameX0;
dstBox.x2 -= pScrn->frameX0;
dstBox.y1 -= pScrn->frameY0;
dstBox.y2 -= pScrn->frameY0;
}
dstPitch = ((width << 1) + 15) & ~15;
new_size = dstPitch * height;
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
srcPitch = (width + 3) & ~3;
offset2 = srcPitch * height;
srcPitch2 = ((width >> 1) + 3) & ~3;
offset3 = (srcPitch2 * (height >> 1)) + offset2;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
srcPitch = (width << 1);
break;
}
pPriv->video_offset = MGAAllocateMemory(pScrn, &pPriv->video_memory,
pPriv->doubleBuffer ?
(new_size << 1) : new_size);
if (!pPriv->video_offset)
return BadAlloc;
pPriv->currentBuffer ^= 1;
/* copy data */
top = y1 >> 16;
left = (x1 >> 16) & ~1;
npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
left <<= 1;
offset = pPriv->video_offset;
if(pPriv->doubleBuffer)
offset += pPriv->currentBuffer * new_size;
dst_start = pMga->FbStart + offset + left + (top * dstPitch);
if (pMga->TexturedVideo && ((long)data != pPriv->lastPort))
MGA_SYNC(pMga, pScrn);
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
top &= ~1;
tmp = ((top >> 1) * srcPitch2) + (left >> 2);
offset2 += tmp;
offset3 += tmp;
if(id == FOURCC_I420) {
tmp = offset2;
offset2 = offset3;
offset3 = tmp;
}
nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
MGACopyMungedData(buf + (top * srcPitch) + (left >> 1),
buf + offset2, buf + offset3, dst_start,
srcPitch, srcPitch2, dstPitch, nlines, npixels);
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
buf += (top * srcPitch) + left;
nlines = ((y2 + 0xffff) >> 16) - top;
MGACopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
break;
}
if(pMga->TexturedVideo) {
pPriv->lastPort = (long)data;
MGADisplayVideoTexture(pScrn, id, offset,
REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes),
width, height, dstPitch, src_x, src_y, src_w, src_h,
drw_x, drw_y, drw_w, drw_h);
pPriv->videoStatus = FREE_TIMER;
pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
} else {
/* update cliplist */
if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
/* draw these */
xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
}
offset += top * dstPitch;
MGADisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
pPriv->videoStatus = CLIENT_VIDEO_ON;
}
pMga->VideoTimerCallback = MGAVideoTimerCallback;
return Success;
}
static int
MGAQueryImageAttributes(
ScrnInfoPtr pScrn,
int id,
unsigned short *w, unsigned short *h,
int *pitches, int *offsets
){
MGAPtr pMga = MGAPTR(pScrn);
int size, tmp;
if(pMga->TexturedVideo) {
if(*w > 2046) *w = 2046;
if(*h > 2046) *h = 2046;
} else {
if(*w > 1024) *w = 1024;
if(*h > 1024) *h = 1024;
}
*w = (*w + 1) & ~1;
if(offsets) offsets[0] = 0;
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
*h = (*h + 1) & ~1;
size = (*w + 3) & ~3;
if(pitches) pitches[0] = size;
size *= *h;
if(offsets) offsets[1] = size;
tmp = ((*w >> 1) + 3) & ~3;
if(pitches) pitches[1] = pitches[2] = tmp;
tmp *= (*h >> 1);
size += tmp;
if(offsets) offsets[2] = size;
size += tmp;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
size = *w << 1;
if(pitches) pitches[0] = size;
size *= *h;
break;
}
return size;
}
static void
MGAVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
{
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
if(pPriv->videoStatus & TIMER_MASK) {
if(pPriv->videoStatus & OFF_TIMER) {
if(pPriv->offTime < time) {
OUTREG(MGAREG_BESCTL, 0);
pPriv->videoStatus = FREE_TIMER;
pPriv->freeTime = time + FREE_DELAY;
}
} else { /* FREE_TIMER */
if(pPriv->freeTime < time) {
if (pPriv->video_memory) {
MGAFreeMemory(pScrn, pPriv->video_memory);
pPriv->video_memory = NULL;
}
pPriv->videoStatus = 0;
pMga->VideoTimerCallback = NULL;
}
}
} else /* shouldn't get here */
pMga->VideoTimerCallback = NULL;
}
/****************** Offscreen stuff ***************/
typedef struct {
void *surface_memory;
Bool isOn;
} OffscreenPrivRec, * OffscreenPrivPtr;
static int
MGAAllocateSurface(
ScrnInfoPtr pScrn,
int id,
unsigned short w,
unsigned short h,
XF86SurfacePtr surface
){
void *surface_memory = NULL;
int pitch, size, bpp, offset;
OffscreenPrivPtr pPriv;
if((w > 1024) || (h > 1024))
return BadAlloc;
w = (w + 1) & ~1;
pitch = ((w << 1) + 15) & ~15;
bpp = pScrn->bitsPerPixel >> 3;
size = ((pitch * h) + bpp - 1) / bpp;
offset = MGAAllocateMemory(pScrn, &surface_memory, size);
if (!offset)
return BadAlloc;
surface->width = w;
surface->height = h;
if(!(surface->pitches = malloc(sizeof(int)))) {
MGAFreeMemory(pScrn, surface_memory);
return BadAlloc;
}
if(!(surface->offsets = malloc(sizeof(int)))) {
free(surface->pitches);
MGAFreeMemory(pScrn, surface_memory);
return BadAlloc;
}
if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
free(surface->pitches);
free(surface->offsets);
MGAFreeMemory(pScrn, surface_memory);
return BadAlloc;
}
pPriv->surface_memory = surface_memory;
pPriv->isOn = FALSE;
surface->pScrn = pScrn;
surface->id = id;
surface->pitches[0] = pitch;
surface->offsets[0] = offset;
surface->devPrivate.ptr = (pointer)pPriv;
return Success;
}
static int
MGAStopSurface(
XF86SurfacePtr surface
){
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
if(pPriv->isOn) {
ScrnInfoPtr pScrn = surface->pScrn;
MGAPtr pMga = MGAPTR(pScrn);
OUTREG(MGAREG_BESCTL, 0);
pPriv->isOn = FALSE;
}
return Success;
}
static int
MGAFreeSurface(
XF86SurfacePtr surface
){
ScrnInfoPtr pScrn = surface->pScrn;
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
if(pPriv->isOn)
MGAStopSurface(surface);
MGAFreeMemory(pScrn, pPriv->surface_memory);
free(surface->pitches);
free(surface->offsets);
free(surface->devPrivate.ptr);
return Success;
}
static int
MGAGetSurfaceAttribute(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 *value
){
return MGAGetPortAttributeOverlay(pScrn, attribute, value, 0);
}
static int
MGASetSurfaceAttribute(
ScrnInfoPtr pScrn,
Atom attribute,
INT32 value
){
return MGASetPortAttributeOverlay(pScrn, attribute, value, 0);
}
static int
MGADisplaySurface(
XF86SurfacePtr surface,
short src_x, short src_y,
short drw_x, short drw_y,
short src_w, short src_h,
short drw_w, short drw_h,
RegionPtr clipBoxes
){
OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
ScrnInfoPtr pScrn = surface->pScrn;
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr portPriv = pMga->portPrivate;
INT32 x1, y1, x2, y2;
BoxRec dstBox;
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
surface->width, surface->height))
{
return Success;
}
dstBox.x1 -= pScrn->frameX0;
dstBox.x2 -= pScrn->frameX0;
dstBox.y1 -= pScrn->frameY0;
dstBox.y2 -= pScrn->frameY0;
MGAResetVideoOverlay(pScrn);
MGADisplayVideoOverlay(pScrn, surface->id, surface->offsets[0],
surface->width, surface->height, surface->pitches[0],
x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
pPriv->isOn = TRUE;
/* we've prempted the XvImage stream so set its free timer */
if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
UpdateCurrentTime();
portPriv->videoStatus = FREE_TIMER;
portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
pMga->VideoTimerCallback = MGAVideoTimerCallback;
}
return Success;
}
static void
MGAInitOffscreenImages(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
MGAPtr pMga = MGAPTR(pScrn);
int num = (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550) ? 2 : 1;
XF86OffscreenImagePtr offscreenImages;
/* need to free this someplace */
if(!(offscreenImages = malloc(num * sizeof(XF86OffscreenImageRec))))
return;
offscreenImages[0].image = &Images[0];
offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
VIDEO_CLIP_TO_VIEWPORT;
offscreenImages[0].alloc_surface = MGAAllocateSurface;
offscreenImages[0].free_surface = MGAFreeSurface;
offscreenImages[0].display = MGADisplaySurface;
offscreenImages[0].stop = MGAStopSurface;
offscreenImages[0].setAttribute = MGASetSurfaceAttribute;
offscreenImages[0].getAttribute = MGAGetSurfaceAttribute;
offscreenImages[0].max_width = 1024;
offscreenImages[0].max_height = 1024;
offscreenImages[0].num_attributes = (num == 1) ? 1 : 4;
offscreenImages[0].attributes = Attributes;
if(num == 2) {
offscreenImages[1].image = &Images[3];
offscreenImages[1].flags = VIDEO_OVERLAID_IMAGES |
VIDEO_CLIP_TO_VIEWPORT;
offscreenImages[1].alloc_surface = MGAAllocateSurface;
offscreenImages[1].free_surface = MGAFreeSurface;
offscreenImages[1].display = MGADisplaySurface;
offscreenImages[1].stop = MGAStopSurface;
offscreenImages[1].setAttribute = MGASetSurfaceAttribute;
offscreenImages[1].getAttribute = MGAGetSurfaceAttribute;
offscreenImages[1].max_width = 1024;
offscreenImages[1].max_height = 1024;
offscreenImages[1].num_attributes = 4;
offscreenImages[1].attributes = Attributes;
}
xf86XVRegisterOffscreenImages(pScreen, offscreenImages, num);
}
/* Matrox MGA 2164W Xv extension support.
* The extension is implemented as a HOST->FB image load in YUV format.
* I decided not to use real hardware overlay since on the Millennium II
* it would limit the size of the frame buffer to 4Mb (even on a 16Mb
* card) due to an hardware limitation.
* Author: Gabriele Gorla (gorlik@yahoo.com)
* Based on the MGA-Gxxx Xv extension by: Mark Vojkovich
*/
/* This code is still in alpha stage. Only YUV->RGB conversion
and horizontal scaling are hardware accelerated.
All 4 FOURCC formats supported by X should be supported.
It has been tested only on my DEC XP1000 at 1024x768x32 under
linux 2.6.18 with X.org 7.1.1 (debian alpha)
Bug reports and success/failure stories are greatly appreciated.
*/
/* #define DEBUG_MGA2164 */
/* #define CUSTOM_MEMCOPY */
#define MGA2164_SWFILTER
static XF86VideoAdaptorPtr
MGASetupImageVideoILOAD(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
XF86VideoAdaptorPtr adapt;
MGAPtr pMga = MGAPTR(pScrn);
adapt = MGAAllocAdaptor(pScrn, FALSE);
if (adapt == NULL)
return NULL;
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = 0;
adapt->name = "Matrox Millennium II ILOAD Video Engine";
adapt->nEncodings = 1;
adapt->pEncodings = &DummyEncoding[1];
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = Formats;
adapt->nPorts = MGA_MAX_PORTS;
adapt->pAttributes = NULL;
adapt->nAttributes = 0;
/* number of supported color formats */
adapt->pImages = Images;
adapt->nImages = 4;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = MGAStopVideo;
adapt->SetPortAttribute = MGASetPortAttributeTexture;
adapt->GetPortAttribute = MGAGetPortAttributeTexture;
adapt->QueryBestSize = MGAQueryBestSize;
adapt->PutImage = MGAPutImageILOAD;
adapt->QueryImageAttributes = MGAQueryImageAttributes;
REGION_INIT(pScreen, &(pMga->portPrivate->clip), NullBox, 0);
return adapt;
}
/* this function is optimized for alpha. It might be better also for
other load/store risc architectures but I never tested on anything else
than my ev56 */
static void CopyMungedScanline_AXP(CARD32 *fb_ptr, short src_w,
CARD32 *tsp, CARD32 *tpu, CARD32 *tpv)
{
CARD32 k,y0,y1,u,v;
for(k=src_w/8;k;k--) {
y0=*tsp;
y1=*(tsp+1);
u=*tpu;
v=*tpv;
*(fb_ptr)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) |
(v&0x00ff0000)<<8 | (u&0x00ff0000)>>8;
*(fb_ptr+1)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) |
(v&0x00ff0000)<<8 | (u&0x00ff0000)>>8;
*(fb_ptr+2)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) |
(v&0x000000ff)<<24 | (u&0x000000ff)<<8;
*(fb_ptr+3)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) |
(v&0x000000ff)<<24 | (u&0x000000ff)<<8;
/*correct below*/
/* *(fb_ptr)=(y0&0x000000ff)|((y0&0x0000ff00)<<8) |
(v&0x000000ff)<<24 | (u&0x000000ff)<<8;
*(fb_ptr+1)=((y0&0x00ff0000)>>16)|((y0&0xff000000)>>8) |
(v&0x0000ff00)<<16 | (u&0x0000ff00);
*(fb_ptr+2)=(y1&0x000000ff)|((y1&0x0000ff00)<<8) |
(v&0x00ff0000)<<8 | (u&0x00ff0000)>>8;
*(fb_ptr+3)=((y1&0x00ff0000)>>16)|((y1&0xff000000)>>8) |
(v&0xff000000) | (u&0xff000000)>>16; */
tsp+=2; tpu++; tpv++;
fb_ptr+=4;
}
}
static void CopyMungedScanline_AXP2(CARD32 *fb_ptr, short src_w,
CARD32 *tsp, CARD32 *tpu, CARD32 *tpv)
{
CARD8 *y, *u, *v;
int k;
y=(CARD8 *)tsp;
u=(CARD8 *)tpu;
v=(CARD8 *)tpv;
for(k=src_w/8;k;k--) {
fb_ptr[0]=y[0] | y[1]<<16 | v[0]<<24 | u[0]<<8;
fb_ptr[1]=y[2] | y[3]<<16 | v[1]<<24 | u[1]<<8;
fb_ptr[2]=y[4] | y[5]<<16 | v[2]<<24 | u[2]<<8;
fb_ptr[3]=y[6] | y[7]<<16 | v[3]<<24 | u[3]<<8;
y+=8; u+=4; v+=4;
fb_ptr+=4;
}
}
static void CopyMungedScanlineFilter_AXP(CARD32 *fb_ptr, short src_w,
CARD32 *tsp1, CARD32 *tpu1, CARD32 *tpv1,
CARD32 *tsp2, CARD32 *tpu2, CARD32 *tpv2,
int beta, int xds )
{
unsigned int k,y0_1,y1_1,y0_2,y1_2,u,v;
int yf[8], uf[4], vf[4];
int oneminbeta = 0xff - beta;
for(k=xds*src_w/8;k;k--) {
y0_1=*tsp1;
y1_1=*(tsp1+1);
y0_2=*tsp2;
y1_2=*(tsp2+1);
u=*tpu1;
v=*tpv1;
tsp1+=2; tsp2+=2; tpu1++; tpv1++;
yf[0] = ((y0_1&0x000000ff)*oneminbeta + (y0_2&0x000000ff)*beta )>>8;
yf[1] = (((y0_1&0x0000ff00)>>8)*oneminbeta + ((y0_2&0x0000ff00)>>8)*beta )>>8;
yf[2] = (((y0_1&0x00ff0000)>>16)*oneminbeta + ((y0_2&0x00ff0000)>>16)*beta )>>8;
yf[3] = (((y0_1&0xff000000)>>24)*oneminbeta + ((y0_2&0xff000000)>>24)*beta )>>8;
yf[4] = ((y1_1&0x000000ff)*oneminbeta + (y1_2&0x000000ff)*beta )>>8;
yf[5] = (((y1_1&0x0000ff00)>>8)*oneminbeta + ((y1_2&0x0000ff00)>>8)*beta )>>8;
yf[6] = (((y1_1&0x00ff0000)>>16)*oneminbeta + ((y1_2&0x00ff0000)>>16)*beta )>>8;
yf[7] = (((y1_1&0xff000000)>>24)*oneminbeta + ((y1_2&0xff000000)>>24)*beta )>>8;
/* FIXME: there is still no filtering on u and v */
uf[0]=(u&0x000000ff);
uf[1]=(u&0x0000ff00)>>8;
uf[2]=(u&0x00ff0000)>>16;
uf[3]=(u&0xff000000)>>24;
vf[0]=(v&0x000000ff);
vf[1]=(v&0x0000ff00)>>8;
vf[2]=(v&0x00ff0000)>>16;
vf[3]=(v&0xff000000)>>24;
switch(xds) {
case 1:
*(fb_ptr)=(yf[0]) | (yf[1]<<16) |
vf[0]<<24 | uf[0]<<8;
*(fb_ptr+1)=(yf[2]) | (yf[3]<<16) |
vf[1]<<24 | uf[1]<<8;
*(fb_ptr+2)=(yf[4]) | (yf[5]<<16) |
vf[2]<<24 | uf[2]<<8;
*(fb_ptr+3)=(yf[6]) | (yf[7]<<16) |
vf[3]<<24 | uf[3]<<8;
fb_ptr+=4;
break;
case 2:
*(fb_ptr)=(yf[0]+yf[1])/2 | (((yf[2]+yf[3])/2)<<16) |
((vf[0]+vf[1])/2 )<<24 | ((uf[0]+uf[1])/2)<<8;
*(fb_ptr+1)=(yf[4]+yf[5])/2 | ( ((yf[6]+yf[7])/2) <<16) |
((vf[2]+vf[3])/2 )<<24 | ((uf[2]+uf[3])/2)<<8;
fb_ptr+=2;
break;
case 4:
*(fb_ptr)=(yf[0]+yf[1]+yf[2]+yf[3])/4 | (((yf[4]+yf[5]+yf[6]+yf[7])/4)<<16) |
((vf[0]+vf[1]+vf[2]+vf[3])/4 )<<24 | ((uf[0]+uf[1]+uf[2]+uf[3])/4)<<8;
fb_ptr+=1;
break;
default:
break;
}
}
}
static void CopyMungedScanlineFilterDown_AXP(CARD32 *fb_ptr, short src_w,
CARD32 *tsp1, CARD32 *tpu1, CARD32 *tpv1,
CARD32 *tsp2, CARD32 *tpu2, CARD32 *tpv2,
int beta , int xds)
{
unsigned int k,y0_1,y1_1,y0_2,y1_2,u,v;
int yf[8], uf[4], vf[4];
for(k=src_w/8;k;k--) {
y0_1=*tsp1;
y1_1=*(tsp1+1);
y0_2=*tsp2;
y1_2=*(tsp2+1);
u=*tpu1;
v=*tpv1;
tsp1+=2; tsp2+=2; tpu1++; tpv1++;
yf[0] = ((y0_1&0x000000ff) + (y0_2&0x000000ff))>>8;
yf[1] = (((y0_1&0x0000ff00)>>8) + ((y0_2&0x0000ff00)>>8))>>8;
yf[2] = (((y0_1&0x00ff0000)>>16) + ((y0_2&0x00ff0000)>>16))>>8;
yf[3] = (((y0_1&0x000000ff)>>24) + ((y0_2&0x000000ff)>>24))>>8;
yf[4] = ((y1_1&0x000000ff) + (y1_2&0x000000ff))>>8;
yf[5] = (((y1_1&0x0000ff00)>>8) + ((y1_2&0x0000ff00)>>8))>>8;
yf[6] = (((y1_1&0x00ff0000)>>16) + ((y1_2&0x00ff0000)>>16))>>8;
yf[7] = (((y1_1&0x000000ff)>>24) + ((y1_2&0x000000ff)>>24))>>8;
*(fb_ptr)=(yf[0]) | (yf[1]<<16) |
(v&0x000000ff)<<24 | (u&0x000000ff)<<8;
*(fb_ptr+1)=(yf[2]) | (yf[3]<<16) |
(v&0x0000ff00)<<16 | (u&0x0000ff00);
*(fb_ptr+2)=(yf[4]) | (yf[5]<<16) |
(v&0x00ff0000)<<8 | (u&0x00ff0000)>>8;
*(fb_ptr+3)=(yf[6]) | (yf[7]<<16) |
(v&0xff000000) | (u&0xff000000)>>16;
fb_ptr+=4;
}
}
static void MGACopyScaledILOAD(
ScrnInfoPtr pScrn,
int id, unsigned char *buf,
BoxPtr pbox,
int width, int height, int pitch,
short src_x, short src_y,
short src_w, short src_h,
short drw_x, short drw_y,
short drw_w, short drw_h
)
{
MGAPtr pMga = MGAPTR(pScrn);
CARD32 *fb_ptr;
unsigned char *ubuf, *vbuf, *tbuf;
CARD32 *pu, *pv;
int k,l, pl, dl, xds, yds;
short box_h;
short scr_pitch = ( pScrn->virtualX + 15) & ~15;
#ifdef DEBUG_MGA2164
char sbuf[255];
sprintf(sbuf,"---- PBOX: x1=%d y1=%d w=%d h=%d (x2=%d y2=%d)\n",
pbox->x1,pbox->y1,pbox->x2-pbox->x1,pbox->y2-pbox->y1,
pbox->x2,pbox->y2);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"in src: src_x=%d src_y=%d src_w=%d src_h=%d\n",
src_x,src_y,src_w,src_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"in drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n",
drw_x,drw_y,drw_w,drw_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
/* scaling yuv->rgb */
/* hack to force width and src image to be 8 pixel aligned */
src_x&=~0x7;
src_w&=~0x7;
box_h=pbox->y2-pbox->y1;
/* compute X down scaling factor */
if(src_w>drw_w) {
if(src_w/2<drw_w) {
xds=2;
} else if(src_w/4<drw_w) {
xds=4;
} else { xds=8; }
} else xds = 1;
/* prevent crashing when dragging window outside left boundary of screen */
/* FIXME: need to implement per pixel left start to avoid undesired
effects when dragging window outside left screen boundary */
if(drw_x<0) {
src_x=( -(drw_x*src_w)/drw_w + 0x7)&~0x7;
src_w-=src_x;
drw_w+=drw_x;
drw_x=0;
}
src_w/=xds;
/* compute X down scaling factor */
if(src_h>drw_h) {
if(src_h/2<drw_h) {
yds=2;
} else if(src_h/4<drw_h) {
yds=4;
} else { yds=8; }
} else yds = 1;
#ifdef DEBUG_MGA2164
char sbuf[255];
sprintf(sbuf,"---- xds = %d\n",
xds);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
#ifdef DEBUG_MGA2164
sprintf(sbuf,"out src: src_x=%d src_y=%d src_w=%d src_h=%d\n",
src_x,src_y,src_w,src_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"out drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n",
drw_x,drw_y,drw_w,drw_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
CHECK_DMA_QUIESCENT(pMga, pScrn);
/* scaling ILOAD */
vbuf=buf+width*height;
ubuf=vbuf+width*height/4;
pu = (CARD32 *)(ubuf+(src_y/2)*(width/2));
pv = (CARD32 *)(vbuf+(src_y/2)*(width/2));
for(pl=-1,dl=0;dl<box_h;dl++) {
int beta;
l=(dl+(pbox->y1-drw_y))*src_h/drw_h;
/* FIXME: check the math */
beta = ((dl+(pbox->y1-drw_y))*src_h*0xff/drw_h) - ((dl+(pbox->y1-drw_y))*src_h/drw_h*0xff);
#ifdef MGA2164_BLIT_DUP
if(l!=pl)
#else
if(1)
#endif
{
/*
#ifdef DEBUG_MGA2164
sprintf(sbuf,"new line: scr_dst %d img_src %d prev %d\n",
dl,l,pl);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
*/
OUTREG(MGAREG_DWGCTL, MGADWG_ILOAD_HIQH | MGADWG_BUYUV | MGADWG_SHIFTZERO
| MGADWG_SGNZERO | 0xc0000);
OUTREG(MGAREG_AR0, pbox->x1 + drw_w -1); /* SRC LINE END why -1 ? */
OUTREG(MGAREG_AR2, ( ( (src_w-1)<<16) / (drw_w-1)) + 1 ); /* ((SRC_X_DIM -1)<<16) / (DST_X_DIM-1) +1 */
OUTREG(MGAREG_AR3, pbox->x1 ); /* SRC LINE START*/
OUTREG(MGAREG_AR5, scr_pitch); /* DST_Y_INCR = PITCH? */
OUTREG(MGAREG_AR6, ((src_w-drw_w)<<16) / (drw_w-1) ); /* */
OUTREG(MGAREG_FXBNDRY, drw_x|((drw_x+drw_w-1)<<16) ); /* why -1 ? */
OUTREG(MGAREG_CXBNDRY, pbox->x1 | ((pbox->x2-1)<<16 ) );
OUTREG(MGAREG_YDST , pbox->y1+dl ); /* Y_START_POS */
OUTREG(MGAREG_LEN + MGAREG_EXEC , 1); /* # of LINES */
/* xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Data finished\n"); */
fb_ptr=(CARD32 *)pMga->ILOADBase;
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
tbuf=buf+(l+src_y)*width;
{
CARD32 *tpu=pu+src_x/8+l/2*width/8;
CARD32 *tpv=pv+src_x/8+l/2*width/8;
CARD32 *tsp=(CARD32 *)(tbuf+src_x), *tsp2;
if((l+src_y)<(src_h-1))
tsp2=(CARD32 *)(tbuf+src_x+width);
else
tsp2=(CARD32 *)(tbuf+src_x);
/* it is not clear if waiting is actually good for performance */
/* WAITFIFO(pMga->FifoSize);*/
/* should try to get MGACopyMunged data to work here */
/* CopyMungedScanline_AXP(fb_ptr,src_w,tsp,tpu,tpv); */
/* Filter does not work yet */
CopyMungedScanlineFilter_AXP(fb_ptr,src_w,tsp,tpu,tpv,tsp2,tpu,tpv, beta, xds);
/* if(l&1) {
pu+=width/8;
pv+=width/8;
} */
}
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
tbuf=buf+(l+src_y)*width*2;
#ifndef MGA2164_SWFILTER
WAITFIFO(pMga->FifoSize/2);
memcpy(fb_ptr, tbuf+src_x*2, src_w*2);
fb_ptr+=src_w*2; /* pointer in the pseudo dma window */
#else
{
CARD32 *tsp=(CARD32 *)(tbuf+src_x*2), *tsp2;
if((l+src_y)<(src_h-1))
tsp2=(CARD32 *)(tbuf+src_x*2+width*2);
else
tsp2=(CARD32 *)(tbuf+src_x*2);
/* {
char sbuf [256];
sprintf(sbuf,"dst line: %d src_line: %d beta: %x\n",
dl, l, beta );
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
} */
WAITFIFO(pMga->FifoSize/4);
for(k=xds*src_w/8;k;k--) {
int oneminbeta = 0xff-beta;
int y[8], u[4], v[4], ya[4], ua[2], va[2], p;
switch(yds) {
case 1:
/* upscale y filter */
for(p=0;p<4;p++) {
y[2*p]=(((*(tsp+p)&0x000000ff))*oneminbeta+((*(tsp2+p)&0x000000ff))*beta)>>8;
y[2*p+1]=(((*(tsp+p)&0x00ff0000)>>16)*oneminbeta+((*(tsp2+p)&0x00ff0000)>>16)*beta)>>8;
u[p]=(((*(tsp+p)&0x0000ff00)>>8)*oneminbeta+((*(tsp2+p)&0x0000ff00)>>8)*beta)>>8;
v[p]=(((*(tsp+p)&0xff000000)>>24)*oneminbeta+((*(tsp2+p)&0xff000000)>>24)*beta)>>8;
}
break;
/* downscale y filter */
case 2:
case 3:
case 4:
default:
for(p=0;p<4;p++) {
y[2*p]=(((*(tsp+p)&0x000000ff)));
y[2*p+1]=(((*(tsp+p)&0x00ff0000)>>16));
u[p]=(((*(tsp+p)&0x0000ff00)>>8));
v[p]=(((*(tsp+p)&0xff000000)>>24));
}
break;
}
switch (xds) {
case 1: /* simple copy */
*(fb_ptr++)=y[0]|y[1]<<16|u[0]<<8|v[0]<<24;
*(fb_ptr++)=y[2]|y[3]<<16|u[1]<<8|v[1]<<24;
*(fb_ptr++)=y[4]|y[5]<<16|u[2]<<8|v[2]<<24;
*(fb_ptr++)=y[6]|y[7]<<16|u[3]<<8|v[3]<<24;
break;
case 2: /* dowscale by 2 */
ya[0]=(y[0]+y[1])>>1;
ya[1]=(y[2]+y[3])>>1;
ya[2]=(y[4]+y[5])>>1;
ya[3]=(y[6]+y[7])>>1;
ua[0]=(u[0]+u[1])>>1;
ua[1]=(u[2]+u[3])>>1;
va[0]=(v[0]+v[1])>>1;
va[1]=(v[2]+v[3])>>1;
*(fb_ptr++)=ya[0]|ya[1]<<16|ua[0]<<8|va[0]<<24;
*(fb_ptr++)=ya[2]|ya[3]<<16|ua[1]<<8|va[1]<<24;
break;
case 4: /* downscale by 4 */
ya[0]=(y[0]+y[1]+y[2]+y[3])>>2;
ya[1]=(y[4]+y[5]+y[6]+y[7])>>2;
ua[0]=(u[0]+u[1]+u[2]+u[3])>>2;
va[0]=(v[0]+v[1]+v[2]+v[3])>>2;
*(fb_ptr++)=ya[0]|ya[1]<<16|ua[0]<<8|va[0]<<24;
break;
case 8:
default:
break;
}
/* fb_ptr+=4; */
tsp+=4; tsp2+=4;
}
}
#endif /* MGA2164_SWFILTER */
break;
default:
break;
}
pl=l;
} else {
/* dup lines */
#ifdef DEBUG_MGA2164
sprintf(sbuf,"dup line: scr_src %d scr_dst %d\n",
dl-1,dl);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
OUTREG(MGAREG_DWGCTL, 0x040C6008);
OUTREG(MGAREG_FXBNDRY, pbox->x1|((pbox->x2-1)<<16) ); /* why -1 ? */
OUTREG(MGAREG_AR3, (pbox->y1+dl-1)*scr_pitch+pbox->x1 ); /* SRC LINE START*/
OUTREG(MGAREG_AR0, (pbox->y1+dl-1)*scr_pitch+pbox->x2 -1); /* SRC LINE END why -1 ? */
OUTREG(MGAREG_AR5, scr_pitch); /* DST_Y_INCR = PITCH? */
OUTREG(MGAREG_YDST , pbox->y1+dl); /* Y_START_POS */
OUTREG(MGAREG_LEN + MGAREG_EXEC , 1); /* # of LINES */
}
}
OUTREG(MGAREG_CXBNDRY, 0xFFFF0000);
}
static void MGACopyILOAD(
ScrnInfoPtr pScrn,
int id, unsigned char *buf,
BoxPtr pbox,
int width, int height, int pitch,
short src_x, short src_y,
short src_w, short src_h,
short drw_x, short drw_y,
short drw_w, short drw_h
)
{
MGAPtr pMga = MGAPTR(pScrn);
CARD32 *fb_ptr;
CARD8 *ubuf, *vbuf;
CARD32 *pu, *pv;
int k,l;
short clip_x1, clip_x2, tmp_w;
#ifdef DEBUG_MGA2164
char sbuf[255];
sprintf(sbuf,"---- PBOX: x1=%d y1=%d w=%d h=%d (x2=%d y2=%d)\n",
pbox->x1,pbox->y1,pbox->x2-pbox->x1,pbox->y2-pbox->y1,
pbox->x2,pbox->y2);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"in src: src_x=%d src_y=%d src_w=%d src_h=%d\n",
src_x,src_y,src_w,src_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"in drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n",
drw_x,drw_y,drw_w,drw_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
/* non-scaling yuv->rgb */
/* hack to force width and src image to be 8 pixel aligned */
src_x&=~0x7;
src_w&=~0x7;
drw_w&=~0x7;
tmp_w=drw_w;
clip_x1=drw_x;
clip_x2=drw_x+drw_w;
/* hack for clipping in non scaling version */
/* this works only if no scaling */
if(pbox->x1 > drw_x) { /* left side X clipping*/
src_x+=((pbox->x1-drw_x)&~0x7);
src_w-=((pbox->x1-drw_x)&~0x7);
clip_x1=pbox->x1;
drw_x+=src_x;
drw_w=src_w;
}
if( (pbox->x2) < (drw_x+drw_w) ) { /* right side X clipping */
tmp_w=( (pbox->x2) - drw_x );
drw_w= tmp_w & (~0x7);
if(drw_w!=tmp_w) drw_w+=8;
clip_x2=drw_x+tmp_w-1; /* not sure why needs -1 */
src_w=drw_w;
}
if(pbox->y1 > drw_y) { /* top side Y clipping */
src_y+=(pbox->y1-drw_y);
src_h-=(pbox->y1-drw_y);
drw_y+=src_y;
drw_h=src_h;
}
if((pbox->y2)<(drw_y+drw_h)) { /* bottom side Y clipping */
drw_h=(pbox->y2)-drw_y;
src_h=drw_h;
}
if(drw_x<0) drw_x=0;
#ifdef DEBUG_MGA2164
sprintf(sbuf,"out src: src_x=%d src_y=%d src_w=%d src_h=%d\n",
src_x,src_y,src_w,src_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
sprintf(sbuf,"out drw: drw_x=%d drw_y=%d drw_w=%d drw_h=%d\n",
drw_x,drw_y,drw_w,drw_h);
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf);
#endif
/* ready to draw */
if(drw_w==0||drw_h==0) return;
if(drw_w<0||drw_h<0) {
/* actually until scaling is working this might happen
during normal operation */
/* sprintf(sbuf,"drw_w or drw_h are negative (this should never
happen)\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, sbuf); */
return;
}
CHECK_DMA_QUIESCENT(pMga, pScrn);
/* non scaling ILOAD */
WAITFIFO(6);
OUTREG(MGAREG_AR5, 0);
OUTREG(MGAREG_DWGCTL, MGADWG_ILOAD | MGADWG_BUYUV | MGADWG_SHIFTZERO
| MGADWG_SGNZERO | 0xc0000);
OUTREG(MGAREG_AR0, (drw_w)-1 );
OUTREG(MGAREG_AR3, 0);
OUTREG(MGAREG_CXBNDRY, clip_x1|(clip_x2<<16));
OUTREG(MGAREG_FXBNDRY, drw_x|((drw_x+drw_w-1)<<16));
OUTREG(MGAREG_YDSTLEN + MGAREG_EXEC , (drw_y<<16)|drw_h);
fb_ptr=(CARD32 *)pMga->ILOADBase;
vbuf=buf+width*height;
ubuf=vbuf+width*height/4;
switch(id) {
case FOURCC_YV12:
case FOURCC_I420:
pu = (CARD32 *)(ubuf+(src_y/2)*(width/2));
pv = (CARD32 *)(vbuf+(src_y/2)*(width/2));
buf+=src_y*width;
for(l=0;l<drw_h;l++) {
CARD32 *tpu=pu+src_x/8;
CARD32 *tpv=pv+src_x/8;
CARD32 *tsp=(CARD32 *)(buf+src_x);
/* it is not clear if waiting is actually good for performance */
/* WAITFIFO(pMga->FifoSize);*/
/* should try to get MGACopyMunged data to work here */
CopyMungedScanline_AXP(fb_ptr,src_w,tsp,tpu,tpv);
buf+=width;
if(l&1) {
pu+=width/8;
pv+=width/8;
}
}
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
buf+=src_y*width*2;
for(l=0;l<drw_h;l++) {
#ifndef CUSTOM_MEMCOPY
WAITFIFO(pMga->FifoSize/2); /* not sure what's the value for best performance */
memcpy(fb_ptr, buf+src_x*2, src_w*2);
fb_ptr+=src_w*2;
#else
CARD32 *tsp=(CARD32 *)(buf+src_x*2);
WAITFIFO(pMga->FifoSize/4);
for(k=src_w/8;k;k--) {
*(fb_ptr)=*(tsp);
*(fb_ptr+1)=*(tsp+1);
*(fb_ptr+2)=*(tsp+2);
*(fb_ptr+3)=*(tsp+3);
fb_ptr+=4; tsp+=4;
}
#endif /* CUSTOM_MEMCOPY */
buf+=width*2;
}
break;
default:
break;
}
OUTREG(MGAREG_CXBNDRY, 0xFFFF0000); /* put clipping back to normal */
}
static int
MGAPutImageILOAD(
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,
DrawablePtr pDraw
){
MGAPtr pMga = MGAPTR(pScrn);
MGAPortPrivPtr pPriv = pMga->portPrivate;
INT32 x1, x2, y1, y2;
int dstPitch = 0;
int bpp;
BoxRec dstBox;
int nbox;
BoxPtr pbox;
/* Clip */
x1 = src_x; x2 = src_x + src_w;
y1 = src_y; y2 = src_y + src_h;
dstBox.x1 = drw_x; dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h;
if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
clipBoxes, width, height))
return Success;
bpp = pScrn->bitsPerPixel >> 3;
#ifdef HAVE_XAA_H
if( pMga->AccelInfoRec->NeedToSync && ((long)data != pPriv->lastPort) ) {
MGAStormSync(pScrn);
}
#endif
pPriv->lastPort = (long)data;
nbox=REGION_NUM_RECTS(clipBoxes);
pbox=REGION_RECTS(clipBoxes);
while(nbox--) {
if ( (drw_w==src_w) && (drw_h==src_h) && (drw_x >= 0 ) ) {
/* special case 1: non scaling optimization */
MGACopyILOAD(pScrn,id,buf,pbox,
width, height, dstPitch, src_x, src_y, src_w, src_h,
drw_x, drw_y, drw_w, drw_h);
#if 0
} else if ( (drw_w>src_w) && (drw_h>src_h) && (drw_x >= 0 ) ) {
/* special case 2: upscaling for full screen apps */
/* FIXME: to do */
MGACopyScaledILOAD(pScrn,id,buf,pbox,
width, height, dstPitch, src_x, src_y, src_w, src_h,
drw_x, drw_y, drw_w, drw_h);
#endif
} else /* generic fallback case */
MGACopyScaledILOAD(pScrn,id,buf,pbox,
width, height, dstPitch, src_x, src_y, src_w, src_h,
drw_x, drw_y, drw_w, drw_h);
/* FIXME: when the generic is perfect I will enable the optimizations */
pbox++;
}
#ifdef HAVE_XAA_H
pMga->AccelInfoRec->NeedToSync = TRUE;
#endif
pPriv->videoStatus = FREE_TIMER;
pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
pMga->VideoTimerCallback = MGAVideoTimerCallback;
return Success;
}