#define VIDEO_DEBUG 0
#include "xf86.h"
#include "xf86_OSproc.h"
#include "xf86Resources.h"
#include "xf86_ansic.h"
#include "compiler.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "xf86fbman.h"
#include "regionstr.h"
#include "i830.h"
#include "xf86xv.h"
#include "Xv.h"
#include "xaa.h"
#include "xaalocal.h"
#include "dixstruct.h"
#include "fourcc.h"
#ifndef USE_USLEEP_FOR_VIDEO
#define USE_USLEEP_FOR_VIDEO 0
#endif
#define OFF_DELAY 250
#define FREE_DELAY 15000
#define OFF_TIMER 0x01
#define FREE_TIMER 0x02
#define CLIENT_VIDEO_ON 0x04
#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
static void I830InitOffscreenImages(ScreenPtr);
static XF86VideoAdaptorPtr I830SetupImageVideo(ScreenPtr);
static void I830StopVideo(ScrnInfoPtr, pointer, Bool);
static int I830SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
static void I830QueryBestSize(ScrnInfoPtr, Bool,
short, short, short, short, unsigned int *,
unsigned int *, pointer);
static int I830PutImage(ScrnInfoPtr, short, short, short, short, short, short,
short, short, int, unsigned char *, short, short,
Bool, RegionPtr, pointer);
static int I830QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
unsigned short *, int *, int *);
static void I830BlockHandler(int, pointer, pointer, pointer);
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
static Atom xvBrightness, xvContrast, xvColorKey;
#define IMAGE_MAX_WIDTH 1440
#define IMAGE_MAX_HEIGHT 1080
#define Y_BUF_SIZE (IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT)
#if !VIDEO_DEBUG
#define ErrorF Edummy
static void
Edummy(const char *dummy, ...)
{
}
#endif
#define OVERLAY_UPDATE \
do { \
BEGIN_LP_RING(6); \
OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); \
OUT_RING(MI_NOOP); \
if (!pI830->overlayOn) { \
OUT_RING(MI_NOOP); \
OUT_RING(MI_NOOP); \
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_ON); \
ErrorF("Overlay goes from off to on\n"); \
pI830->overlayOn = TRUE; \
} else { \
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \
OUT_RING(MI_NOOP); \
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE); \
} \
OUT_RING(pI830->OverlayMem.Physical | 1); \
ADVANCE_LP_RING(); \
ErrorF("OVERLAY_UPDATE\n"); \
} while(0)
#define OVERLAY_OFF \
do { \
if (pI830->overlayOn) { \
BEGIN_LP_RING(8); \
OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); \
OUT_RING(MI_NOOP); \
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \
OUT_RING(MI_NOOP); \
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_OFF); \
OUT_RING(pI830->OverlayMem.Physical); \
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); \
OUT_RING(MI_NOOP); \
ADVANCE_LP_RING(); \
pI830->overlayOn = FALSE; \
ErrorF("Overlay goes from on to off\n"); \
ErrorF("OVERLAY_OFF\n"); \
} \
} while(0)
#define MIRROR_MODE (0x3<<17)
#define MIRROR_HORIZONTAL (0x1<<17)
#define MIRROR_VERTICAL (0x2<<17)
#define MIRROR_BOTH (0x3<<17)
#define OV_BYTE_ORDER (0x3<<14)
#define UV_SWAP (0x1<<14)
#define Y_SWAP (0x2<<14)
#define Y_AND_UV_SWAP (0x3<<14)
#define SOURCE_FORMAT (0xf<<10)
#define RGB_888 (0x1<<10)
#define RGB_555 (0x2<<10)
#define RGB_565 (0x3<<10)
#define YUV_422 (0x8<<10)
#define YUV_411 (0x9<<10)
#define YUV_420 (0xc<<10)
#define YUV_422_PLANAR (0xd<<10)
#define YUV_410 (0xe<<10)
#define TVSYNC_FLIP_PARITY (0x1<<9)
#define TVSYNC_FLIP_ENABLE (0x1<<7)
#define BUF_TYPE (0x1<<5)
#define BUF_TYPE_FRAME (0x0<<5)
#define BUF_TYPE_FIELD (0x1<<5)
#define TEST_MODE (0x1<<4)
#define BUFFER_SELECT (0x3<<2)
#define BUFFER0 (0x0<<2)
#define BUFFER1 (0x1<<2)
#define FIELD_SELECT (0x1<<1)
#define FIELD0 (0x0<<1)
#define FIELD1 (0x1<<1)
#define OVERLAY_ENABLE 0x1
#define CC_OUT_8BIT (0x1<<3)
#define OVERLAY_PIPE_MASK (0x1<<18)
#define OVERLAY_PIPE_A (0x0<<18)
#define OVERLAY_PIPE_B (0x1<<18)
#define DEST_KEY_ENABLE (0x1<<31)
#define N_HORIZ_Y_TAPS 5
#define N_VERT_Y_TAPS 3
#define N_HORIZ_UV_TAPS 3
#define N_VERT_UV_TAPS 3
#define N_PHASES 17
#define MAX_TAPS 5
#define MIN_CUTOFF_FREQ 1.0
#define MAX_CUTOFF_FREQ 3.0
#define RGB16ToColorKey(c) \
(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
#define RGB15ToColorKey(c) \
(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
static XF86VideoEncodingRec DummyEncoding[1] = {
{
0,
"XV_IMAGE",
IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
{1, 1}
}
};
#define NUM_FORMATS 3
static XF86VideoFormatRec Formats[NUM_FORMATS] = {
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
};
#define NUM_ATTRIBUTES 3
static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
};
#define NUM_IMAGES 4
static XF86ImageRec Images[NUM_IMAGES] = {
XVIMAGE_YUY2,
XVIMAGE_YV12,
XVIMAGE_I420,
XVIMAGE_UYVY
};
typedef struct {
CARD32 OBUF_0Y;
CARD32 OBUF_1Y;
CARD32 OBUF_0U;
CARD32 OBUF_0V;
CARD32 OBUF_1U;
CARD32 OBUF_1V;
CARD32 OSTRIDE;
CARD32 YRGB_VPH;
CARD32 UV_VPH;
CARD32 HORZ_PH;
CARD32 INIT_PHS;
CARD32 DWINPOS;
CARD32 DWINSZ;
CARD32 SWIDTH;
CARD32 SWIDTHSW;
CARD32 SHEIGHT;
CARD32 YRGBSCALE;
CARD32 UVSCALE;
CARD32 OCLRC0;
CARD32 OCLRC1;
CARD32 DCLRKV;
CARD32 DCLRKM;
CARD32 SCLRKVH;
CARD32 SCLRKVL;
CARD32 SCLRKEN;
CARD32 OCONFIG;
CARD32 OCMD;
CARD32 RESERVED1;
CARD32 AWINPOS;
CARD32 AWINSZ;
CARD32 RESERVED2;
CARD32 RESERVED3;
CARD32 RESERVED4;
CARD32 RESERVED5;
CARD32 RESERVED6;
CARD32 RESERVED7;
CARD32 RESERVED8;
CARD32 RESERVED9;
CARD32 RESERVEDA;
CARD32 RESERVEDB;
CARD32 FASTHSCALE;
CARD32 UVSCALEV;
CARD32 RESERVEDC[(0x200 - 0xA8) / 4];
CARD16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES];
CARD16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
CARD16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES];
CARD16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
CARD16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES];
CARD16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
CARD16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES];
CARD16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
} I830OverlayRegRec, *I830OverlayRegPtr;
typedef struct {
CARD32 GAMC5;
CARD32 GAMC4;
CARD32 GAMC3;
CARD32 GAMC2;
CARD32 GAMC1;
CARD32 GAMC0;
} I830OverlayStateRec, *I830OverlayStatePtr;
typedef struct {
CARD32 YBuf0offset;
CARD32 UBuf0offset;
CARD32 VBuf0offset;
CARD32 YBuf1offset;
CARD32 UBuf1offset;
CARD32 VBuf1offset;
unsigned char currentBuf;
int brightness;
int contrast;
RegionRec clip;
CARD32 colorKey;
CARD32 videoStatus;
Time offTime;
Time freeTime;
FBLinearPtr linear;
I830OverlayStateRec hwstate;
Bool refreshOK;
int maxRate;
} I830PortPrivRec, *I830PortPrivPtr;
#define GET_PORT_PRIVATE(pScrn) \
(I830PortPrivPtr)((I830PTR(pScrn))->adaptor->pPortPrivates[0].ptr)
static void
CompareOverlay(I830Ptr pI830, CARD32 * overlay, int size)
{
int i;
CARD32 val;
int bad = 0;
for (i = 0; i < size; i += 4) {
val = INREG(0x30100 + i);
if (val != overlay[i / 4]) {
ErrorF("0x%05x value doesn't match (0x%08x != 0x%08x)\n",
0x30100 + i, val, overlay[i / 4]);
bad++;
}
}
if (!bad)
ErrorF("CompareOverlay: no differences\n");
}
void
I830InitVideo(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
XF86VideoAdaptorPtr newAdaptor = NULL;
int num_adaptors;
DPRINTF(PFX, "I830InitVideo\n");
#if 0
{
I830OverlayRegRec tmp;
ErrorF("sizeof I830OverlayRegRec is 0x%x\n", sizeof(I830OverlayRegRec));
ErrorF("Reserved C, D, E, F, G are %x, %x, %x, %x, %x\n",
(unsigned long)&(tmp.RESERVEDC[0]) - (unsigned long)&tmp,
(unsigned long)&(tmp.RESERVEDD[0]) - (unsigned long)&tmp,
(unsigned long)&(tmp.RESERVEDE[0]) - (unsigned long)&tmp,
(unsigned long)&(tmp.RESERVEDF[0]) - (unsigned long)&tmp,
(unsigned long)&(tmp.RESERVEDG[0]) - (unsigned long)&tmp);
}
#endif
if (pScrn->bitsPerPixel != 8) {
newAdaptor = I830SetupImageVideo(pScreen);
I830InitOffscreenImages(pScreen);
}
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
if (newAdaptor) {
if (!num_adaptors) {
num_adaptors = 1;
adaptors = &newAdaptor;
} else {
newAdaptors =
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);
}
static void
I830ResetVideo(ScrnInfoPtr pScrn)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
I830OverlayStatePtr hwstate = &(pPriv->hwstate);
DPRINTF(PFX, "I830ResetVideo: base: %p, offset: 0x%08x, obase: %p\n",
pI830->FbBase, pI830->OverlayMem.Start, overlay);
memset(overlay, 0, sizeof(*overlay));
overlay->YRGB_VPH = 0;
overlay->UV_VPH = 0;
overlay->HORZ_PH = 0;
overlay->INIT_PHS = 0;
overlay->DWINPOS = 0;
overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH;
overlay->SWIDTH = IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 16);
overlay->SWIDTHSW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12);
overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15);
overlay->OCLRC0 = 0x01000000;
overlay->OCLRC1 = 0x00000080;
overlay->AWINPOS = 0;
overlay->AWINSZ = 0;
overlay->FASTHSCALE = 0;
switch (pScrn->depth) {
case 8:
overlay->DCLRKV = 0;
overlay->DCLRKM = 0xffffff | DEST_KEY_ENABLE;
break;
case 15:
overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
overlay->DCLRKM = 0x070707 | DEST_KEY_ENABLE;
break;
case 16:
overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
overlay->DCLRKM = 0x070307 | DEST_KEY_ENABLE;
break;
default:
overlay->DCLRKV = pPriv->colorKey;
overlay->DCLRKM = DEST_KEY_ENABLE;
break;
}
overlay->SCLRKVH = 0;
overlay->SCLRKVL = 0;
overlay->SCLRKEN = 0;
overlay->OCONFIG = CC_OUT_8BIT;
if (pI830->pipeEnabled[0])
overlay->OCONFIG |= OVERLAY_PIPE_A;
else if (pI830->pipeEnabled[1])
overlay->OCONFIG |= OVERLAY_PIPE_B;
overlay->OCMD = YUV_420;
hwstate->GAMC5 = 0xc0c0c0;
hwstate->GAMC4 = 0x808080;
hwstate->GAMC3 = 0x404040;
hwstate->GAMC2 = 0x202020;
hwstate->GAMC1 = 0x101010;
hwstate->GAMC0 = 0x080808;
#if 0
{
int i;
for (i = 0x30000; i < 0x31000; i += 4)
ErrorF("0x%x 0x%08x\n", i, INREG(i));
}
#endif
OUTREG(OGAMC5, hwstate->GAMC5);
OUTREG(OGAMC4, hwstate->GAMC4);
OUTREG(OGAMC3, hwstate->GAMC3);
OUTREG(OGAMC2, hwstate->GAMC2);
OUTREG(OGAMC1, hwstate->GAMC1);
OUTREG(OGAMC0, hwstate->GAMC0);
}
#define I830_OVERLAY_RATE 79
#define I845_OVERLAY_RATE 120
#define I852_OVERLAY_RATE 79
#define I855_OVERLAY_RATE 120
#define I865_OVERLAY_RATE 170
#define DEFAULT_OVERLAY_RATE 120
static XF86VideoAdaptorPtr
I830SetupImageVideo(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
I830Ptr pI830 = I830PTR(pScrn);
XF86VideoAdaptorPtr adapt;
I830PortPrivPtr pPriv;
DPRINTF(PFX, "I830SetupImageVideo\n");
if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
sizeof(I830PortPrivRec) + sizeof(DevUnion))))
return NULL;
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
adapt->name = "Intel(R) 830M/845G/852GM/855GM/865G Video Overlay";
adapt->nEncodings = 1;
adapt->pEncodings = DummyEncoding;
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = Formats;
adapt->nPorts = 1;
adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
pPriv = (I830PortPrivPtr) (&adapt->pPortPrivates[1]);
adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
adapt->pAttributes = Attributes;
adapt->nImages = NUM_IMAGES;
adapt->nAttributes = NUM_ATTRIBUTES;
adapt->pImages = Images;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = I830StopVideo;
adapt->SetPortAttribute = I830SetPortAttribute;
adapt->GetPortAttribute = I830GetPortAttribute;
adapt->QueryBestSize = I830QueryBestSize;
adapt->PutImage = I830PutImage;
adapt->QueryImageAttributes = I830QueryImageAttributes;
pPriv->colorKey = pI830->colorKey & ((1 << pScrn->depth) - 1);
pPriv->videoStatus = 0;
pPriv->brightness = 0;
pPriv->contrast = 64;
pPriv->linear = NULL;
pPriv->currentBuf = 0;
switch (pI830->PciInfo->chipType) {
case PCI_CHIP_I830_M:
pPriv->maxRate = I830_OVERLAY_RATE;
break;
case PCI_CHIP_845_G:
pPriv->maxRate = I845_OVERLAY_RATE;
break;
case PCI_CHIP_I855_GM:
switch (pI830->variant) {
case I852_GM:
case I852_GME:
pPriv->maxRate = I852_OVERLAY_RATE;
break;
default:
pPriv->maxRate = I855_OVERLAY_RATE;
break;
}
break;
case PCI_CHIP_I865_G:
pPriv->maxRate = I865_OVERLAY_RATE;
break;
default:
pPriv->maxRate = DEFAULT_OVERLAY_RATE;
break;
}
REGION_NULL(pScreen, &pPriv->clip);
pI830->adaptor = adapt;
pPriv->refreshOK = TRUE;
I830VideoSwitchModeAfter(pScrn, pScrn->currentMode);
pI830->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = I830BlockHandler;
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
xvColorKey = MAKE_ATOM("XV_COLORKEY");
I830ResetVideo(pScrn);
return adapt;
}
static void
I830StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
{
I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
I830Ptr pI830 = I830PTR(pScrn);
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
DPRINTF(PFX, "I830StopVideo\n");
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
if (shutdown) {
if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
overlay->OCMD &= ~OVERLAY_ENABLE;
OVERLAY_UPDATE;
OVERLAY_OFF;
}
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
I830SetPortAttribute(ScrnInfoPtr pScrn,
Atom attribute, INT32 value, pointer data)
{
I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
I830Ptr pI830 = I830PTR(pScrn);
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
if (attribute == xvBrightness) {
if ((value < -128) || (value > 127))
return BadValue;
pPriv->brightness = value;
overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
if (pPriv->refreshOK)
OVERLAY_UPDATE;
} else if (attribute == xvContrast) {
if ((value < 0) || (value > 255))
return BadValue;
pPriv->contrast = value;
overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
if (pPriv->refreshOK)
OVERLAY_UPDATE;
} else if (attribute == xvColorKey) {
pPriv->colorKey = value;
switch (pScrn->depth) {
case 16:
overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
break;
case 15:
overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
break;
default:
overlay->DCLRKV = pPriv->colorKey;
break;
}
if (pPriv->refreshOK)
OVERLAY_UPDATE;
REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
} else
return BadMatch;
return Success;
}
static int
I830GetPortAttribute(ScrnInfoPtr pScrn,
Atom attribute, INT32 * value, pointer data)
{
I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
if (attribute == xvBrightness) {
*value = pPriv->brightness;
} else if (attribute == xvContrast) {
*value = pPriv->contrast;
} else if (attribute == xvColorKey) {
*value = pPriv->colorKey;
} else
return BadMatch;
return Success;
}
static void
I830QueryBestSize(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 << 1))
drw_w = vid_w >> 1;
if (vid_h > (drw_h << 1))
drw_h = vid_h >> 1;
*p_w = drw_w;
*p_h = drw_h;
}
static void
I830CopyPackedData(ScrnInfoPtr pScrn,
unsigned char *buf,
int srcPitch,
int dstPitch, int top, int left, int h, int w)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
unsigned char *src, *dst;
DPRINTF(PFX, "I830CopyPackedData: (%d,%d) (%d,%d)\n"
"srcPitch: %d, dstPitch: %d\n", top, left, h, w, srcPitch, dstPitch);
src = buf + (top * srcPitch) + (left << 1);
if (pPriv->currentBuf == 0)
dst = pI830->FbBase + pPriv->YBuf0offset;
else
dst = pI830->FbBase + pPriv->YBuf1offset;
w <<= 1;
while (h--) {
memcpy(dst, src, w);
src += srcPitch;
dst += dstPitch;
}
}
static void
I830CopyPlanarData(ScrnInfoPtr pScrn, unsigned char *buf, int srcPitch,
int dstPitch, int srcH, int top, int left,
int h, int w, int id)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
int i;
unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3;
DPRINTF(PFX, "I830CopyPlanarData: srcPitch %d, dstPitch %d\n"
"nlines %d, npixels %d, top %d, left %d\n", srcPitch, dstPitch,
h, w, top, left);
src1 = buf + (top * srcPitch) + left;
ErrorF("src1 is %p, offset is %d\n", src1,
(unsigned long)src1 - (unsigned long)buf);
if (pPriv->currentBuf == 0)
dst1 = pI830->FbBase + pPriv->YBuf0offset;
else
dst1 = pI830->FbBase + pPriv->YBuf1offset;
for (i = 0; i < h; i++) {
memcpy(dst1, src1, w);
src1 += srcPitch;
dst1 += dstPitch << 1;
}
src2 = buf + (srcH * srcPitch) + ((top * srcPitch) >> 2) + (left >> 1);
ErrorF("src2 is %p, offset is %d\n", src2,
(unsigned long)src2 - (unsigned long)buf);
if (pPriv->currentBuf == 0) {
if (id == FOURCC_I420)
dst2 = pI830->FbBase + pPriv->UBuf0offset;
else
dst2 = pI830->FbBase + pPriv->VBuf0offset;
} else {
if (id == FOURCC_I420)
dst2 = pI830->FbBase + pPriv->UBuf1offset;
else
dst2 = pI830->FbBase + pPriv->VBuf1offset;
}
for (i = 0; i < h / 2; i++) {
memcpy(dst2, src2, w / 2);
src2 += srcPitch >> 1;
dst2 += dstPitch;
}
src3 = buf + (srcH * srcPitch) + ((srcH * srcPitch) >> 2) +
((top * srcPitch) >> 2) + (left >> 1);
ErrorF("src3 is %p, offset is %d\n", src3,
(unsigned long)src3 - (unsigned long)buf);
if (pPriv->currentBuf == 0) {
if (id == FOURCC_I420)
dst3 = pI830->FbBase + pPriv->VBuf0offset;
else
dst3 = pI830->FbBase + pPriv->UBuf0offset;
} else {
if (id == FOURCC_I420)
dst3 = pI830->FbBase + pPriv->VBuf1offset;
else
dst3 = pI830->FbBase + pPriv->UBuf1offset;
}
for (i = 0; i < h / 2; i++) {
memcpy(dst3, src3, w / 2);
src3 += srcPitch >> 1;
dst3 += dstPitch;
}
}
typedef struct {
CARD8 sign;
CARD16 mantissa;
CARD8 exponent;
} coeffRec, *coeffPtr;
static Bool
SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos)
{
int maxVal, icoeff, res;
int sign;
double c;
sign = 0;
maxVal = 1 << mantSize;
c = *coeff;
if (c < 0.0) {
sign = 1;
c = -c;
}
res = 12 - mantSize;
if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) {
pCoeff[pos].exponent = 3;
pCoeff[pos].mantissa = icoeff << res;
*coeff = (double)icoeff / (double)(4 * maxVal);
} else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) {
pCoeff[pos].exponent = 2;
pCoeff[pos].mantissa = icoeff << res;
*coeff = (double)icoeff / (double)(2 * maxVal);
} else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) {
pCoeff[pos].exponent = 1;
pCoeff[pos].mantissa = icoeff << res;
*coeff = (double)icoeff / (double)(maxVal);
} else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) {
pCoeff[pos].exponent = 0;
pCoeff[pos].mantissa = icoeff << res;
*coeff = (double)icoeff / (double)(maxVal / 2);
} else {
return FALSE;
}
pCoeff[pos].sign = sign;
if (sign)
*coeff = -(*coeff);
return TRUE;
}
static void
UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff)
{
int i, j, j1, num, pos, mantSize;
double pi = 3.1415926535, val, sinc, window, sum;
double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS];
double diff;
int tapAdjust[MAX_TAPS], tap2Fix;
Bool isVertAndUV;
if (isHoriz)
mantSize = 7;
else
mantSize = 6;
isVertAndUV = !isHoriz && !isY;
num = taps * 16;
for (i = 0; i < num * 2; i++) {
val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num);
if (val == 0.0)
sinc = 1.0;
else
sinc = sin(val) / val;
window = (0.5 - 0.5 * cos(i * pi / num));
rawCoeff[i] = sinc * window;
}
for (i = 0; i < N_PHASES; i++) {
sum = 0.0;
for (j = 0; j < taps; j++) {
pos = i + j * 32;
sum += rawCoeff[pos];
}
for (j = 0; j < taps; j++) {
pos = i + j * 32;
coeffs[i][j] = rawCoeff[pos] / sum;
}
for (j = 0; j < taps; j++) {
pos = j + i * taps;
if ((j == (taps - 1) / 2) && !isVertAndUV)
SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos);
else
SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos);
}
tapAdjust[0] = (taps - 1) / 2;
for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) {
tapAdjust[j1] = tapAdjust[0] - j;
tapAdjust[++j1] = tapAdjust[0] + j;
}
sum = 0.0;
for (j = 0; j < taps; j++)
sum += coeffs[i][j];
if (sum != 1.0) {
for (j1 = 0; j1 < taps; j1++) {
tap2Fix = tapAdjust[j1];
diff = 1.0 - sum;
coeffs[i][tap2Fix] += diff;
pos = tap2Fix + i * taps;
if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV)
SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos);
else
SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos);
sum = 0.0;
for (j = 0; j < taps; j++)
sum += coeffs[i][j];
if (sum == 1.0)
break;
}
}
}
}
static void
I830DisplayVideo(ScrnInfoPtr pScrn, int id, short width, short height,
int dstPitch, int x1, int y1, int x2, int y2, BoxPtr dstBox,
short src_w, short src_h, short drw_w, short drw_h)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
unsigned int swidth;
DPRINTF(PFX, "I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
dstPitch);
if (!pPriv->refreshOK)
return;
CompareOverlay(pI830, (CARD32 *) overlay, 0x100);
switch (id) {
case FOURCC_YV12:
case FOURCC_I420:
swidth = (width + 1) & ~1 & 0xfff;
overlay->SWIDTH = swidth;
swidth /= 2;
overlay->SWIDTH |= (swidth & 0x7ff) << 16;
swidth = ((pPriv->YBuf0offset + width + 0x1f) >> 5) -
(pPriv->YBuf0offset >> 5) - 1;
ErrorF("Y width is %d, swidthsw is %d\n", width, swidth);
overlay->SWIDTHSW = swidth << 2;
swidth = ((pPriv->UBuf0offset + (width / 2) + 0x1f) >> 5) -
(pPriv->UBuf0offset >> 5) - 1;
ErrorF("UV width is %d, swidthsw is %d\n", width / 2, swidth);
overlay->SWIDTHSW |= swidth << 18;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
swidth = ((width + 31) & ~31) << 1;
overlay->SWIDTH = swidth;
overlay->SWIDTHSW = swidth >> 3;
break;
}
overlay->SHEIGHT = height | ((height / 2) << 16);
overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1;
overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) |
(dstBox->x2 - dstBox->x1);
overlay->OBUF_0Y = pPriv->YBuf0offset;
overlay->OBUF_1Y = pPriv->YBuf1offset;
overlay->OBUF_0U = pPriv->UBuf0offset;
overlay->OBUF_0V = pPriv->VBuf0offset;
overlay->OBUF_1U = pPriv->UBuf1offset;
overlay->OBUF_1V = pPriv->VBuf1offset;
ErrorF("Buffers: Y0: 0x%08x, U0: 0x%08x, V0: 0x%08x\n", overlay->OBUF_0Y,
overlay->OBUF_0U, overlay->OBUF_0V);
ErrorF("Buffers: Y1: 0x%08x, U1: 0x%08x, V1: 0x%08x\n", overlay->OBUF_1Y,
overlay->OBUF_1U, overlay->OBUF_1V);
#if 0
{
int i;
ErrorF("First 32 bytes of Y data:\n");
for (i = 0; i < 32; i++)
ErrorF(" %02x",
((unsigned char *)pI830->FbBase + pPriv->YBuf0offset)[i]);
ErrorF("\n");
ErrorF("First 16 bytes of U data:\n");
for (i = 0; i < 16; i++)
ErrorF(" %02x",
((unsigned char *)pI830->FbBase + pPriv->UBuf0offset)[i]);
ErrorF("\n");
ErrorF("First 16 bytes of V data:\n");
for (i = 0; i < 16; i++)
ErrorF(" %02x",
((unsigned char *)pI830->FbBase + pPriv->VBuf0offset)[i]);
ErrorF("\n");
}
#endif
#if 1
overlay->OCMD = OVERLAY_ENABLE;
#endif
ErrorF("pos: 0x%08x, size: 0x%08x\n", overlay->DWINPOS, overlay->DWINSZ);
ErrorF("dst: %d x %d, src: %d x %d\n", drw_w, drw_h, src_w, src_h);
{
Bool scaleChanged = FALSE;
int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
int xscaleIntUV, xscaleFractUV;
int yscaleIntUV, yscaleFractUV;
int uvratio = 2;
CARD32 newval;
coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
int i, j, pos;
xscaleFract = (src_w << 12) / drw_w;
yscaleFract = (src_h << 12) / drw_h;
xscaleFractUV = xscaleFract / uvratio;
yscaleFractUV = yscaleFract / uvratio;
xscaleFract = xscaleFractUV * uvratio;
yscaleFract = yscaleFractUV * uvratio;
xscaleInt = xscaleFract >> 12;
yscaleInt = yscaleFract >> 12;
xscaleIntUV = xscaleFractUV >> 12;
yscaleIntUV = yscaleFractUV >> 12;
ErrorF("xscale: 0x%x.%03x, yscale: 0x%x.%03x\n", xscaleInt,
xscaleFract & 0xFFF, yscaleInt, yscaleFract & 0xFFF);
ErrorF("UV xscale: 0x%x.%03x, UV yscale: 0x%x.%03x\n", xscaleIntUV,
xscaleFractUV & 0xFFF, yscaleIntUV, yscaleFractUV & 0xFFF);
newval = (xscaleInt << 16) |
((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
if (newval != overlay->YRGBSCALE) {
scaleChanged = TRUE;
overlay->YRGBSCALE = newval;
}
newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) |
((yscaleFractUV & 0xFFF) << 20);
if (newval != overlay->UVSCALE) {
scaleChanged = TRUE;
overlay->UVSCALE = newval;
}
newval = yscaleInt << 16 | yscaleIntUV;
if (newval != overlay->UVSCALEV) {
scaleChanged = TRUE;
overlay->UVSCALEV = newval;
}
if (scaleChanged) {
double fCutoffY;
double fCutoffUV;
fCutoffY = xscaleFract / 4096.0;
fCutoffUV = xscaleFractUV / 4096.0;
if (fCutoffY < MIN_CUTOFF_FREQ)
fCutoffY = MIN_CUTOFF_FREQ;
if (fCutoffY > MAX_CUTOFF_FREQ)
fCutoffY = MAX_CUTOFF_FREQ;
if (fCutoffUV < MIN_CUTOFF_FREQ)
fCutoffUV = MIN_CUTOFF_FREQ;
if (fCutoffUV > MAX_CUTOFF_FREQ)
fCutoffUV = MAX_CUTOFF_FREQ;
UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY);
UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV);
for (i = 0; i < N_PHASES; i++) {
for (j = 0; j < N_HORIZ_Y_TAPS; j++) {
pos = i * N_HORIZ_Y_TAPS + j;
overlay->Y_HCOEFS[pos] = xcoeffY[pos].sign << 15 |
xcoeffY[pos].exponent << 12 |
xcoeffY[pos].mantissa;
}
}
for (i = 0; i < N_PHASES; i++) {
for (j = 0; j < N_HORIZ_UV_TAPS; j++) {
pos = i * N_HORIZ_UV_TAPS + j;
overlay->UV_HCOEFS[pos] = xcoeffUV[pos].sign << 15 |
xcoeffUV[pos].exponent << 12 |
xcoeffUV[pos].mantissa;
}
}
}
}
switch (id) {
case FOURCC_YV12:
case FOURCC_I420:
ErrorF("YUV420\n");
#if 0
overlay->UV_VPH = 0x30003000;
#endif
ErrorF("UV stride is %d, Y stride is %d\n", dstPitch, dstPitch * 2);
overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16);
overlay->OCMD &= ~SOURCE_FORMAT;
overlay->OCMD &= ~OV_BYTE_ORDER;
overlay->OCMD |= YUV_420;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
ErrorF("YUV422\n");
overlay->OSTRIDE = dstPitch;
overlay->OCMD &= ~SOURCE_FORMAT;
overlay->OCMD |= YUV_422;
overlay->OCMD &= ~OV_BYTE_ORDER;
if (id == FOURCC_UYVY)
overlay->OCMD |= Y_SWAP;
break;
}
overlay->OCMD &= ~(BUFFER_SELECT | FIELD_SELECT);
if (pPriv->currentBuf == 0)
overlay->OCMD |= BUFFER0;
else
overlay->OCMD |= BUFFER1;
ErrorF("OCMD is 0x%08x\n", overlay->OCMD);
OVERLAY_UPDATE;
}
static FBLinearPtr
I830AllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
{
ScreenPtr pScreen;
FBLinearPtr new_linear;
int bytespp = pScrn->bitsPerPixel >> 3;
DPRINTF(PFX, "I830AllocateMemory\n");
size = (size + bytespp - 1) / bytespp;
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, 4,
NULL, NULL, NULL);
if (!new_linear) {
int max_size;
xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4,
PRIORITY_EXTREME);
if (max_size < size)
return NULL;
xf86PurgeUnlockedOffscreenAreas(pScreen);
new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4,
NULL, NULL, NULL);
}
return new_linear;
}
static int
I830PutImage(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)
{
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
INT32 x1, x2, y1, y2;
int srcPitch, dstPitch;
int top, left, npixels, nlines, size, loops;
BoxRec dstBox;
DPRINTF(PFX, "I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n"
"width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, drw_y,
drw_w, drw_h, width, height);
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
width, height))
return Success;
dstBox.x1 -= pScrn->frameX0;
dstBox.x2 -= pScrn->frameX0;
dstBox.y1 -= pScrn->frameY0;
dstBox.y2 -= pScrn->frameY0;
switch (id) {
case FOURCC_YV12:
case FOURCC_I420:
srcPitch = (width + 3) & ~3;
dstPitch = ((width / 2) + 255) & ~255;
size = dstPitch * height * 3;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
srcPitch = (width << 1);
dstPitch = (srcPitch + 255) & ~255;
size = dstPitch * height;
break;
}
ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, dstPitch, size);
if (!(pPriv->linear = I830AllocateMemory(pScrn, pPriv->linear,
size * 2 / pI830->cpp)))
return BadAlloc;
pPriv->YBuf0offset = pScrn->fbOffset + pPriv->linear->offset * pI830->cpp;
pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height);
pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height / 2);
pPriv->YBuf1offset = pPriv->YBuf0offset + size;
pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height);
pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height / 2);
loops = 0;
while (loops < 1000000) {
#if USE_USLEEP_FOR_VIDEO
usleep(10);
#endif
if (((INREG(DOVSTA) & OC_BUF) >> 20) == pPriv->currentBuf) {
break;
}
loops++;
}
if (loops >= 1000000) {
ErrorF("loops (1) maxed out for buffer %d\n", pPriv->currentBuf);
#if 0
pPriv->currentBuf = !pPriv->currentBuf;
#endif
}
if (pPriv->currentBuf == 0)
pPriv->currentBuf = 1;
else
pPriv->currentBuf = 0;
top = y1 >> 16;
left = (x1 >> 16) & ~1;
npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
switch (id) {
case FOURCC_YV12:
case FOURCC_I420:
top &= ~1;
nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
I830CopyPlanarData(pScrn, buf, srcPitch, dstPitch, height, top, left,
nlines, npixels, id);
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
nlines = ((y2 + 0xffff) >> 16) - top;
I830CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines,
npixels);
break;
}
if (1 || !REGION_EQUAL(pScreen, &pPriv->clip, clipBoxes)) {
REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
xf86XVFillKeyHelper(pScreen, pPriv->colorKey, clipBoxes);
}
I830DisplayVideo(pScrn, id, width, height, dstPitch,
x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
pPriv->videoStatus = CLIENT_VIDEO_ON;
return Success;
}
static int
I830QueryImageAttributes(ScrnInfoPtr pScrn,
int id,
unsigned short *w, unsigned short *h,
int *pitches, int *offsets)
{
int size, tmp;
DPRINTF(PFX, "I830QueryImageAttributes: w is %d, h is %d\n", *w, *h);
if (*w > IMAGE_MAX_WIDTH)
*w = IMAGE_MAX_WIDTH;
if (*h > IMAGE_MAX_HEIGHT)
*h = IMAGE_MAX_HEIGHT;
*w = (*w + 1) & ~1;
if (offsets)
offsets[0] = 0;
switch (id) {
case FOURCC_IA44:
case FOURCC_AI44:
if (pitches)
pitches[0] = *w;
size = *w * *h;
break;
case FOURCC_YV12:
case FOURCC_I420:
*h = (*h + 1) & ~1;
#if 1
size = (*w + 3) & ~3;
#else
size = (*w + 255) & ~255;
#endif
if (pitches)
pitches[0] = size;
size *= *h;
if (offsets)
offsets[1] = size;
#if 1
tmp = ((*w >> 1) + 3) & ~3;
#else
tmp = ((*w >> 1) + 255) & ~255;
#endif
if (pitches)
pitches[1] = pitches[2] = tmp;
tmp *= (*h >> 1);
size += tmp;
if (offsets)
offsets[2] = size;
size += tmp;
if (pitches)
ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", pitches[0],
pitches[1], pitches[2]);
if (offsets)
ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], offsets[2]);
if (offsets)
ErrorF("size is %d\n", size);
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
size = *w << 1;
if (pitches)
pitches[0] = size;
size *= *h;
break;
}
return size;
}
static void
I830BlockHandler(int i,
pointer blockData, pointer pTimeout, pointer pReadmask)
{
ScreenPtr pScreen = screenInfo.screens[i];
ScrnInfoPtr pScrn = xf86Screens[i];
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
pScreen->BlockHandler = pI830->BlockHandler;
(*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
pScreen->BlockHandler = I830BlockHandler;
if (pPriv->videoStatus & TIMER_MASK) {
UpdateCurrentTime();
if (pPriv->videoStatus & OFF_TIMER) {
if (pPriv->offTime < currentTime.milliseconds) {
overlay->OCMD &= ~OVERLAY_ENABLE;
OVERLAY_UPDATE;
OVERLAY_OFF;
pPriv->videoStatus = FREE_TIMER;
pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
}
} else {
if (pPriv->freeTime < currentTime.milliseconds) {
if (pPriv->linear) {
xf86FreeOffscreenLinear(pPriv->linear);
pPriv->linear = NULL;
}
pPriv->videoStatus = 0;
}
}
}
}
typedef struct {
FBLinearPtr linear;
Bool isOn;
} OffscreenPrivRec, *OffscreenPrivPtr;
static int
I830AllocateSurface(ScrnInfoPtr pScrn,
int id,
unsigned short w,
unsigned short h, XF86SurfacePtr surface)
{
FBLinearPtr linear;
int pitch, fbpitch, size, bpp;
OffscreenPrivPtr pPriv;
I830Ptr pI830 = I830PTR(pScrn);
DPRINTF(PFX, "I830AllocateSurface\n");
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 = I830AllocateMemory(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;
memset(pI830->FbBase + pScrn->fbOffset + surface->offsets[0], 0, size);
return Success;
}
static int
I830StopSurface(XF86SurfacePtr surface)
{
OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr;
ScrnInfoPtr pScrn = surface->pScrn;
if (pPriv->isOn) {
I830Ptr pI830 = I830PTR(pScrn);
I830OverlayRegPtr overlay =
(I830OverlayRegPtr) (pI830->FbBase + pI830->OverlayMem.Start);
overlay->OCMD &= ~OVERLAY_ENABLE;
OVERLAY_UPDATE;
OVERLAY_OFF;
pPriv->isOn = FALSE;
}
return Success;
}
static int
I830FreeSurface(XF86SurfacePtr surface)
{
OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr;
if (pPriv->isOn) {
I830StopSurface(surface);
}
xf86FreeOffscreenLinear(pPriv->linear);
xfree(surface->pitches);
xfree(surface->offsets);
xfree(surface->devPrivate.ptr);
return Success;
}
static int
I830GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 * value)
{
return I830GetPortAttribute(pScrn, attribute, value, 0);
}
static int
I830SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
{
return I830SetPortAttribute(pScrn, attribute, value, 0);
}
static int
I830DisplaySurface(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;
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
I830Ptr pI830 = I830PTR(pScrn);
I830PortPrivPtr pI830Priv = GET_PORT_PRIVATE(pScrn);
INT32 x1, y1, x2, y2;
INT32 loops = 0;
BoxRec dstBox;
DPRINTF(PFX, "I830DisplaySurface\n");
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;
pI830Priv->YBuf0offset = surface->offsets[0];
pI830Priv->YBuf1offset = pI830Priv->YBuf0offset;
while (((INREG(DOVSTA) & OC_BUF) >> 20) != pI830Priv->currentBuf) {
#if USE_USLEEP_FOR_VIDEO
usleep(10);
#endif
if (loops == 200000) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n");
break;
}
loops++;
}
if (pI830Priv->currentBuf == 0)
pI830Priv->currentBuf = 1;
else
pI830Priv->currentBuf = 0;
I830ResetVideo(pScrn);
I830DisplayVideo(pScrn, surface->id, surface->width, surface->height,
surface->pitches[0], x1, y1, x2, y2, &dstBox,
src_w, src_h, drw_w, drw_h);
xf86XVFillKeyHelper(pScreen, pI830Priv->colorKey, clipBoxes);
pPriv->isOn = TRUE;
if (pI830Priv->videoStatus & CLIENT_VIDEO_ON) {
REGION_EMPTY(pScrn->pScreen, &pI830Priv->clip);
UpdateCurrentTime();
pI830Priv->videoStatus = FREE_TIMER;
pI830Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
pScrn->pScreen->BlockHandler = I830BlockHandler;
}
return Success;
}
static void
I830InitOffscreenImages(ScreenPtr pScreen)
{
XF86OffscreenImagePtr offscreenImages;
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 = I830AllocateSurface;
offscreenImages[0].free_surface = I830FreeSurface;
offscreenImages[0].display = I830DisplaySurface;
offscreenImages[0].stop = I830StopSurface;
offscreenImages[0].setAttribute = I830SetSurfaceAttribute;
offscreenImages[0].getAttribute = I830GetSurfaceAttribute;
offscreenImages[0].max_width = 1024;
offscreenImages[0].max_height = 1024;
offscreenImages[0].num_attributes = 1;
offscreenImages[0].attributes = Attributes;
xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
}
void
I830VideoSwitchModeBefore(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
I830PortPrivPtr pPriv;
int pixrate;
if (!I830PTR(pScrn)->adaptor) {
return;
}
pPriv = GET_PORT_PRIVATE(pScrn);
if (!pPriv) {
xf86ErrorF("pPriv isn't set\n");
return;
}
pixrate = mode->HDisplay * mode->VDisplay * mode->VRefresh;
if (pixrate > pPriv->maxRate && pPriv->refreshOK) {
I830StopVideo(pScrn, pPriv, TRUE);
pPriv->refreshOK = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling XVideo output because the mode pixel rate (%d MHz)\n"
"\texceeds the hardware limit (%d MHz).\n", pixrate, pPriv->maxRate);
}
}
void
I830VideoSwitchModeAfter(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
I830PortPrivPtr pPriv;
int pixrate;
if (!I830PTR(pScrn)->adaptor) {
return;
}
pPriv = GET_PORT_PRIVATE(pScrn);
if (!pPriv)
return;
if (mode->VRefresh == 0)
mode->VRefresh = 60;
pixrate = (mode->HDisplay * mode->VDisplay * mode->VRefresh) / 1000000;
if (pPriv->refreshOK && pixrate > pPriv->maxRate) {
pPriv->refreshOK = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling XVideo output because the mode pixel rate (%d MHz)\n"
"\texceeds the hardware limit (%d MHz)\n", pixrate, pPriv->maxRate);
} else if (!pPriv->refreshOK && pixrate <= pPriv->maxRate) {
pPriv->refreshOK = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Enabling XVideo output (mode pixel rate %d MHz is within limits).\n",
pixrate);
}
}