1017 lines
25 KiB
C
1017 lines
25 KiB
C
/*
|
|
* Copyright © 2003 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <kdrive-config.h>
|
|
#endif
|
|
#include "nvidia.h"
|
|
|
|
#include <X11/extensions/Xv.h>
|
|
#include "fourcc.h"
|
|
|
|
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
|
|
|
|
static Atom xvBrightness, xvSaturation, xvColorKey;
|
|
|
|
#define IMAGE_MAX_WIDTH 720
|
|
#define IMAGE_MAX_HEIGHT 576
|
|
|
|
static void
|
|
nvidiaStopVideo(KdScreenInfo *screen, pointer data, Bool exit)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
Reg *reg = nvidiac->reg;
|
|
MediaReg *media = nvidiac->media_reg;
|
|
|
|
REGION_EMPTY(screen->pScreen, &pPortPriv->clip);
|
|
|
|
if (!media)
|
|
return;
|
|
|
|
if(pPortPriv->videoOn)
|
|
{
|
|
nvidiaWaitIdle (reg);
|
|
/* wait for buffer to be displayed */
|
|
while (((media->TRIG_CNTL >> 5) & 1) != pPortPriv->currentBuf)
|
|
;
|
|
/* wait for buffer to be finished */
|
|
while (((media->TRIG_CNTL >> 6) & 1) != 0)
|
|
;
|
|
nvidiaWaitAvail (reg, 1);
|
|
media->OVERLAY_SCALE_CNTL = 0;
|
|
pPortPriv->videoOn = FALSE;
|
|
nvidiaWaitIdle (reg);
|
|
}
|
|
}
|
|
|
|
static int
|
|
nvidiaSetPortAttribute(KdScreenInfo *screen,
|
|
Atom attribute,
|
|
int value,
|
|
pointer data)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
MediaReg *media = nvidiac->media_reg;
|
|
|
|
if(attribute == xvBrightness)
|
|
{
|
|
if(value < -1000)
|
|
value = -1000;
|
|
if (value > 1000)
|
|
value = 1000;
|
|
pPortPriv->brightness = value;
|
|
}
|
|
else if(attribute == xvSaturation)
|
|
{
|
|
if (value < -1000)
|
|
value = -1000;
|
|
if (value > 1000)
|
|
value = 1000;
|
|
pPortPriv->saturation = value;
|
|
}
|
|
else if(attribute == xvColorKey)
|
|
{
|
|
if (pPortPriv->colorKey != value)
|
|
{
|
|
pPortPriv->colorKey = value;
|
|
REGION_EMPTY(screen->pScreen, &pPortPriv->clip);
|
|
}
|
|
}
|
|
else
|
|
return BadMatch;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
nvidiaGetPortAttribute(KdScreenInfo *screen,
|
|
Atom attribute,
|
|
int *value,
|
|
pointer data)
|
|
{
|
|
NvidiaPortPrivPtr pPortPriv = (NvidiaPortPrivPtr)data;
|
|
|
|
if(attribute == xvBrightness)
|
|
*value = pPortPriv->brightness;
|
|
else if(attribute == xvSaturation)
|
|
*value = pPortPriv->saturation;
|
|
else if(attribute == xvColorKey)
|
|
*value = pPortPriv->colorKey;
|
|
else
|
|
return BadMatch;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
nvidiaQueryBestSize(KdScreenInfo *screen,
|
|
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
|
|
nvidiaCopyPackedData(KdScreenInfo *screen,
|
|
unsigned char *buf,
|
|
int randr,
|
|
int srcPitch,
|
|
int dstPitch,
|
|
int srcW,
|
|
int srcH,
|
|
int top,
|
|
int left,
|
|
int h,
|
|
int w)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
CARD8 *src, *dst;
|
|
int srcDown, srcRight, srcNext;
|
|
int p;
|
|
|
|
switch (randr & RR_Rotate_All) {
|
|
case RR_Rotate_0:
|
|
src = buf;
|
|
srcDown = srcPitch;
|
|
srcRight = 2;
|
|
break;
|
|
case RR_Rotate_90:
|
|
src = buf + (srcH - 1) * 2;
|
|
srcDown = -2;
|
|
srcRight = srcPitch;
|
|
break;
|
|
case RR_Rotate_180:
|
|
src = buf + srcPitch * (srcH - 1) + (srcW - 1) * 2;
|
|
srcDown = -srcPitch;
|
|
srcRight = -2;
|
|
break;
|
|
case RR_Rotate_270:
|
|
src = buf + srcPitch * (srcW - 1);
|
|
srcDown = 2;
|
|
srcRight = -srcPitch;
|
|
break;
|
|
}
|
|
|
|
src = src + top*srcDown + left*srcRight;
|
|
|
|
if (pPortPriv->currentBuf == 0)
|
|
dst = (CARD8 *) nvidias->vesa.fb + pPortPriv->YBuf0Offset;
|
|
else
|
|
dst = (CARD8 *) nvidias->vesa.fb + pPortPriv->YBuf1Offset;
|
|
|
|
w >>= 1;
|
|
srcRight >>= 1;
|
|
srcNext = srcRight >> 1;
|
|
while(h--)
|
|
{
|
|
CARD16 *s = (CARD16 *) src;
|
|
CARD32 *d = (CARD32 *) dst;
|
|
p = w;
|
|
while (p--)
|
|
{
|
|
*d++ = s[0] | (s[srcNext] << 16);
|
|
s += srcRight;
|
|
}
|
|
src += srcPitch;
|
|
dst += dstPitch;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nvidiaCopyPlanarData(KdScreenInfo *screen,
|
|
unsigned char *buf,
|
|
int randr,
|
|
int srcPitch,
|
|
int srcPitch2,
|
|
int dstPitch, /* of chroma */
|
|
int srcW,
|
|
int srcH,
|
|
int height,
|
|
int top,
|
|
int left,
|
|
int h,
|
|
int w,
|
|
int id)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
int i, j;
|
|
CARD8 *src1, *src2, *src3, *dst1;
|
|
int srcDown, srcDown2, srcRight, srcRight2, srcNext;
|
|
|
|
/* compute source data pointers */
|
|
src1 = buf;
|
|
src2 = src1 + height * srcPitch;
|
|
src3 = src2 + (height >> 1) * srcPitch2;
|
|
switch (randr & RR_Rotate_All) {
|
|
case RR_Rotate_0:
|
|
srcDown = srcPitch;
|
|
srcDown2 = srcPitch2;
|
|
srcRight = 2;
|
|
srcRight2 = 1;
|
|
srcNext = 1;
|
|
break;
|
|
case RR_Rotate_90:
|
|
src1 = src1 + srcH - 1;
|
|
src2 = src2 + (srcH >> 1) - 1;
|
|
src3 = src3 + (srcH >> 1) - 1;
|
|
srcDown = -1;
|
|
srcDown2 = -1;
|
|
srcRight = srcPitch * 2;
|
|
srcRight2 = srcPitch2;
|
|
srcNext = srcPitch;
|
|
break;
|
|
case RR_Rotate_180:
|
|
src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1);
|
|
src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1);
|
|
src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1);
|
|
srcDown = -srcPitch;
|
|
srcDown2 = -srcPitch2;
|
|
srcRight = -2;
|
|
srcRight2 = -1;
|
|
srcNext = -1;
|
|
break;
|
|
case RR_Rotate_270:
|
|
src1 = src1 + srcPitch * (srcW - 1);
|
|
src2 = src2 + srcPitch2 * ((srcW >> 1) - 1);
|
|
src3 = src3 + srcPitch2 * ((srcW >> 1) - 1);
|
|
srcDown = 1;
|
|
srcDown2 = 1;
|
|
srcRight = -srcPitch * 2;
|
|
srcRight2 = -srcPitch2;
|
|
srcNext = -srcPitch;
|
|
break;
|
|
}
|
|
|
|
/* adjust for origin */
|
|
src1 += top * srcDown + left * srcNext;
|
|
src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2;
|
|
src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2;
|
|
|
|
if (id == FOURCC_I420)
|
|
{
|
|
CARD8 *srct = src2;
|
|
src2 = src3;
|
|
src3 = srct;
|
|
}
|
|
|
|
if (pPortPriv->currentBuf == 0)
|
|
dst1 = (CARD8 *) nvidias->vesa.fb + pPortPriv->YBuf0Offset;
|
|
else
|
|
dst1 = (CARD8 *) nvidias->vesa.fb + pPortPriv->YBuf1Offset;
|
|
|
|
w >>= 1;
|
|
for (j = 0; j < h; j++)
|
|
{
|
|
CARD32 *dst = (CARD32 *) dst1;
|
|
CARD8 *s1l = src1;
|
|
CARD8 *s1r = src1 + srcNext;
|
|
CARD8 *s2 = src2;
|
|
CARD8 *s3 = src3;
|
|
|
|
for (i = 0; i < w; i++)
|
|
{
|
|
*dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24);
|
|
s1l += srcRight;
|
|
s1r += srcRight;
|
|
s2 += srcRight2;
|
|
s3 += srcRight2;
|
|
}
|
|
src1 += srcDown;
|
|
dst1 += dstPitch;
|
|
if (j & 1)
|
|
{
|
|
src2 += srcDown2;
|
|
src3 += srcDown2;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
nvidiaPaintRegion (ScreenPtr pScreen, RegionPtr pRgn, Pixel fg)
|
|
{
|
|
WindowPtr pRoot = WindowTable[pScreen->myNum];
|
|
GCPtr pGC;
|
|
CARD32 val[2];
|
|
xRectangle *rects, *r;
|
|
BoxPtr pBox = REGION_RECTS (pRgn);
|
|
int nBox = REGION_NUM_RECTS (pRgn);
|
|
|
|
rects = xalloc (nBox * sizeof (xRectangle));
|
|
if (!rects)
|
|
goto bail0;
|
|
r = rects;
|
|
while (nBox--)
|
|
{
|
|
r->x = pBox->x1;
|
|
r->y = pBox->y1;
|
|
r->width = pBox->x2 - pBox->x1;
|
|
r->height = pBox->y2 - pBox->y1;
|
|
r++;
|
|
pBox++;
|
|
}
|
|
|
|
pGC = GetScratchGC (pRoot->drawable.depth, pScreen);
|
|
if (!pGC)
|
|
goto bail1;
|
|
|
|
val[0] = fg;
|
|
val[1] = IncludeInferiors;
|
|
ChangeGC (pGC, GCForeground|GCSubwindowMode, val);
|
|
|
|
ValidateGC (&pRoot->drawable, pGC);
|
|
|
|
(*pGC->ops->PolyFillRect) (&pRoot->drawable, pGC,
|
|
REGION_NUM_RECTS (pRgn), rects);
|
|
|
|
FreeScratchGC (pGC);
|
|
bail1:
|
|
xfree (rects);
|
|
bail0:
|
|
;
|
|
}
|
|
|
|
/* NvidiaClipVideo -
|
|
|
|
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 (x1, y1
|
|
inclusive, x2, y2 exclusive) and returned are the new source
|
|
boundaries in 16.16 fixed point.
|
|
*/
|
|
|
|
static void
|
|
NvidiaClipVideo(BoxPtr dst,
|
|
INT32 *x1,
|
|
INT32 *x2,
|
|
INT32 *y1,
|
|
INT32 *y2,
|
|
BoxPtr extents, /* extents of the clip region */
|
|
INT32 width,
|
|
INT32 height)
|
|
{
|
|
INT32 vscale, hscale, delta;
|
|
int diff;
|
|
|
|
hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
|
|
vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
|
|
|
|
*x1 <<= 16; *x2 <<= 16;
|
|
*y1 <<= 16; *y2 <<= 16;
|
|
|
|
diff = extents->x1 - dst->x1;
|
|
if(diff > 0) {
|
|
dst->x1 = extents->x1;
|
|
*x1 += diff * hscale;
|
|
}
|
|
diff = dst->x2 - extents->x2;
|
|
if(diff > 0) {
|
|
dst->x2 = extents->x2;
|
|
*x2 -= diff * hscale;
|
|
}
|
|
diff = extents->y1 - dst->y1;
|
|
if(diff > 0) {
|
|
dst->y1 = extents->y1;
|
|
*y1 += diff * vscale;
|
|
}
|
|
diff = dst->y2 - extents->y2;
|
|
if(diff > 0) {
|
|
dst->y2 = extents->y2;
|
|
*y2 -= diff * vscale;
|
|
}
|
|
|
|
if(*x1 < 0) {
|
|
diff = (- *x1 + hscale - 1)/ hscale;
|
|
dst->x1 += diff;
|
|
*x1 += diff * hscale;
|
|
}
|
|
delta = *x2 - (width << 16);
|
|
if(delta > 0) {
|
|
diff = (delta + hscale - 1)/ hscale;
|
|
dst->x2 -= diff;
|
|
*x2 -= diff * hscale;
|
|
}
|
|
if(*y1 < 0) {
|
|
diff = (- *y1 + vscale - 1)/ vscale;
|
|
dst->y1 += diff;
|
|
*y1 += diff * vscale;
|
|
}
|
|
delta = *y2 - (height << 16);
|
|
if(delta > 0) {
|
|
diff = (delta + vscale - 1)/ vscale;
|
|
dst->y2 -= diff;
|
|
*y2 -= diff * vscale;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nvidiaDisplayVideo(KdScreenInfo *screen,
|
|
int id,
|
|
int dstPitch, /* of chroma for 4:2:0 */
|
|
int x1,
|
|
int y1,
|
|
int x2,
|
|
int y2,
|
|
int dst_x1,
|
|
int dst_y1,
|
|
int dst_x2,
|
|
int dst_y2,
|
|
short src_w,
|
|
short src_h,
|
|
short drw_w,
|
|
short drw_h)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
Reg *reg = nvidiac->reg;
|
|
MediaReg *media = nvidiac->media_reg;
|
|
int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
|
|
int xscaleIntUV = 0, xscaleFractUV = 0;
|
|
int yscaleIntUV = 0, yscaleFractUV = 0;
|
|
int randr = nvidias->vesa.randr;
|
|
int HORZ_INC, VERT_INC;
|
|
CARD32 SCALER_IN;
|
|
CARD32 OVERLAY_SCALE_CNTL;
|
|
int tmp;
|
|
int left;
|
|
int bright;
|
|
int sat;
|
|
|
|
if (id == FOURCC_UYVY)
|
|
SCALER_IN = SCALER_IN_YVYU422;
|
|
else
|
|
SCALER_IN = SCALER_IN_VYUY422;
|
|
|
|
nvidiaWaitAvail (reg, 4);
|
|
|
|
media->VIDEO_FORMAT = SCALER_IN | VIDEO_IN_VYUY422;
|
|
|
|
/* color key */
|
|
media->OVERLAY_GRAPHICS_KEY_MSK = (1 << screen->fb[0].depth) - 1;
|
|
media->OVERLAY_GRAPHICS_KEY_CLR = pPortPriv->colorKey;
|
|
/* set key control to obey only graphics color key */
|
|
media->OVERLAY_KEY_CNTL = 0x50;
|
|
|
|
nvidiaWaitAvail (reg, 9);
|
|
media->CAPTURE_DEBUG = 0;
|
|
/* no exclusive video region */
|
|
media->OVERLAY_EXCLUSIVE_HORZ = 0;
|
|
media->OVERLAY_EXCLUSIVE_VERT = 0;
|
|
/* scaling coefficients */
|
|
media->SCALER_H_COEFF0 = 0x00002000;
|
|
media->SCALER_H_COEFF1 = 0x0D06200D;
|
|
media->SCALER_H_COEFF2 = 0x0D0A1C0D;
|
|
media->SCALER_H_COEFF3 = 0x0C0E1A0C;
|
|
media->SCALER_H_COEFF4 = 0x0C14140C;
|
|
media->SCALER_TEST = 0;
|
|
|
|
nvidiaWaitAvail (reg, 2);
|
|
media->OVERLAY_SCALE_CNTL = (SCALE_PIX_EXPAND |
|
|
SCALE_GAMMA_BRIGHT |
|
|
SCALE_BANDWIDTH |
|
|
SCALE_OVERLAY_EN |
|
|
SCALE_EN);
|
|
|
|
bright = (pPortPriv->brightness * 64 / 1000);
|
|
if (bright < -0x40)
|
|
bright = -0x40;
|
|
if (bright > 0x3f)
|
|
bright = 0x3f;
|
|
bright = bright & 0x7f;
|
|
sat = ((pPortPriv->saturation * 31 + 31000) / 2000);
|
|
if (sat > 0x1f)
|
|
sat = 0x1f;
|
|
if (sat < 0)
|
|
sat = 0;
|
|
|
|
media->SCALER_COLOUR_CNTL = ((bright << 0) | /* BRIGHTNESS */
|
|
(sat << 8) | /* SATURATION_U */
|
|
(sat << 16) | /* SATURATION_V */
|
|
(0 << 21) | /* SCALER_VERT_ADJ_UV */
|
|
(0 << 28)); /* SCALER_HORZ_ADJ_UV */
|
|
|
|
VERT_INC = (src_h << 12) / drw_h;
|
|
HORZ_INC = (src_w << 12) / drw_w;
|
|
|
|
nvidiaWaitAvail (reg, 13);
|
|
|
|
/* lock registers to prevent non-atomic update */
|
|
media->OVERLAY_Y_X_START = 0x80000000 | NVIDIA_YX (dst_x1, dst_y1);
|
|
/* ending screen coordinate */
|
|
media->OVERLAY_Y_X_END = 0x80000000 | NVIDIA_YX (dst_x2, dst_y2);
|
|
|
|
media->OVERLAY_SCALE_INC = NVIDIA_YX(HORZ_INC, VERT_INC);
|
|
|
|
media->SCALER_BUF0_OFFSET = pPortPriv->YBuf0Offset;
|
|
media->SCALER_BUF1_OFFSET = pPortPriv->YBuf1Offset;
|
|
|
|
media->SCALER_BUF0_OFFSET_U = pPortPriv->YBuf0Offset;
|
|
media->SCALER_BUF1_OFFSET_U = pPortPriv->YBuf1Offset;
|
|
|
|
media->SCALER_BUF0_OFFSET_V = pPortPriv->YBuf0Offset;
|
|
media->SCALER_BUF1_OFFSET_V = pPortPriv->YBuf1Offset;
|
|
|
|
media->SCALER_BUF_PITCH = dstPitch >> 1;
|
|
media->SCALER_HEIGHT_WIDTH = NVIDIA_YX(src_w - (x1 >> 16), src_h - (y1 >> 16));
|
|
|
|
media->CAPTURE_CONFIG = pPortPriv->currentBuf << 28;
|
|
|
|
/* set XY location and unlock */
|
|
media->OVERLAY_Y_X_START = NVIDIA_YX (dst_x1, dst_y1);
|
|
}
|
|
|
|
static int
|
|
nvidiaPutImage(KdScreenInfo *screen,
|
|
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)
|
|
{
|
|
KdCardInfo *card = screen->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = (NvidiaPortPrivPtr)data;
|
|
Reg *reg = nvidiac->reg;
|
|
MediaReg *media = nvidiac->media_reg;
|
|
INT32 x1, x2, y1, y2;
|
|
int randr = nvidias->vesa.randr;
|
|
int srcPitch, srcPitch2, dstPitch;
|
|
int top, left, npixels, nlines, size;
|
|
BoxRec dstBox;
|
|
int dst_width = width, dst_height = height;
|
|
int rot_x1, rot_y1, rot_x2, rot_y2;
|
|
int dst_x1, dst_y1, dst_x2, dst_y2;
|
|
int rot_src_w, rot_src_h, rot_drw_w, rot_drw_h;
|
|
|
|
/* 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;
|
|
|
|
NvidiaClipVideo(&dstBox, &x1, &x2, &y1, &y2,
|
|
REGION_EXTENTS(pScreen, clipBoxes), width, height);
|
|
|
|
if((x1 >= x2) || (y1 >= y2))
|
|
return Success;
|
|
|
|
if (!media)
|
|
return BadAlloc;
|
|
|
|
if (randr & (RR_Rotate_0|RR_Rotate_180))
|
|
{
|
|
dst_width = width;
|
|
dst_height = height;
|
|
rot_src_w = src_w;
|
|
rot_src_h = src_h;
|
|
rot_drw_w = drw_w;
|
|
rot_drw_h = drw_h;
|
|
}
|
|
else
|
|
{
|
|
dst_width = height;
|
|
dst_height = width;
|
|
rot_src_w = src_h;
|
|
rot_src_h = src_w;
|
|
rot_drw_w = drw_h;
|
|
rot_drw_h = drw_w;
|
|
}
|
|
|
|
switch (randr & RR_Rotate_All) {
|
|
case RR_Rotate_0:
|
|
dst_x1 = dstBox.x1;
|
|
dst_y1 = dstBox.y1;
|
|
dst_x2 = dstBox.x2;
|
|
dst_y2 = dstBox.y2;
|
|
rot_x1 = x1;
|
|
rot_y1 = y1;
|
|
rot_x2 = x2;
|
|
rot_y2 = y2;
|
|
break;
|
|
case RR_Rotate_90:
|
|
dst_x1 = dstBox.y1;
|
|
dst_y1 = screen->height - dstBox.x2;
|
|
dst_x2 = dstBox.y2;
|
|
dst_y2 = screen->height - dstBox.x1;
|
|
|
|
rot_x1 = y1;
|
|
rot_y1 = (src_w << 16) - x2;
|
|
rot_x2 = y2;
|
|
rot_y2 = (src_w << 16) - x1;
|
|
break;
|
|
case RR_Rotate_180:
|
|
dst_x1 = screen->width - dstBox.x2;
|
|
dst_y1 = screen->height - dstBox.y2;
|
|
dst_x2 = screen->width - dstBox.x1;
|
|
dst_y2 = screen->height - dstBox.y1;
|
|
rot_x1 = (src_w << 16) - x2;
|
|
rot_y1 = (src_h << 16) - y2;
|
|
rot_x2 = (src_w << 16) - x1;
|
|
rot_y2 = (src_h << 16) - y1;
|
|
break;
|
|
case RR_Rotate_270:
|
|
dst_x1 = screen->width - dstBox.y2;
|
|
dst_y1 = dstBox.x1;
|
|
dst_x2 = screen->width - dstBox.y1;
|
|
dst_y2 = dstBox.x2;
|
|
rot_x1 = (src_h << 16) - y2;
|
|
rot_y1 = x1;
|
|
rot_x2 = (src_h << 16) - y1;
|
|
rot_y2 = x2;
|
|
break;
|
|
}
|
|
|
|
switch(id) {
|
|
case FOURCC_YV12:
|
|
case FOURCC_I420:
|
|
dstPitch = ((dst_width << 1) + 15) & ~15;
|
|
srcPitch = (width + 3) & ~3;
|
|
srcPitch2 = ((width >> 1) + 3) & ~3;
|
|
size = dstPitch * (int) dst_height;
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
dstPitch = ((dst_width << 1) + 15) & ~15;
|
|
srcPitch = (width << 1);
|
|
size = dstPitch * (int) dst_height;
|
|
break;
|
|
}
|
|
|
|
pPortPriv->offset = nvidias->off_screen - (CARD8 *) nvidias->vesa.fb;
|
|
/* fixup pointers */
|
|
|
|
pPortPriv->YBuf0Offset = pPortPriv->offset;
|
|
pPortPriv->YBuf1Offset = pPortPriv->offset + size;
|
|
|
|
#if 0
|
|
nvidiaWaitIdle (reg);
|
|
|
|
if (pPortPriv->videoOn)
|
|
{
|
|
/* wait for buffer to be displayed */
|
|
while (((media->TRIG_CNTL >> 5) & 1) != pPortPriv->currentBuf)
|
|
;
|
|
}
|
|
#endif
|
|
/*
|
|
* Use the other buffer
|
|
*/
|
|
pPortPriv->currentBuf = 1 - pPortPriv->currentBuf;
|
|
|
|
/* copy data */
|
|
top = rot_y1 >> 16;
|
|
left = (rot_x1 >> 16) & ~1;
|
|
npixels = ((((rot_x2 + 0xffff) >> 16) + 1) & ~1) - left;
|
|
|
|
switch(id) {
|
|
case FOURCC_YV12:
|
|
case FOURCC_I420:
|
|
top &= ~1;
|
|
nlines = ((((rot_y2 + 0xffff) >> 16) + 1) & ~1) - top;
|
|
nvidiaCopyPlanarData(screen, buf, randr,
|
|
srcPitch, srcPitch2, dstPitch,
|
|
rot_src_w, rot_src_h, height,
|
|
top, left, nlines, npixels, id);
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
nlines = ((rot_y2 + 0xffff) >> 16) - top;
|
|
nvidiaCopyPackedData(screen, buf, randr,
|
|
srcPitch, dstPitch,
|
|
rot_src_w, rot_src_h,
|
|
top, left, nlines,
|
|
npixels);
|
|
break;
|
|
}
|
|
|
|
nvidiaDisplayVideo(screen, id, dstPitch,
|
|
rot_x1, rot_y1, rot_x2, rot_y2,
|
|
dst_x1, dst_y1,
|
|
dst_x2, dst_y2,
|
|
rot_src_w, rot_src_h, rot_drw_w, rot_drw_h);
|
|
|
|
/* update cliplist */
|
|
if (!REGION_EQUAL (screen->pScreen, &pPortPriv->clip, clipBoxes))
|
|
{
|
|
REGION_COPY (screen->pScreen, &pPortPriv->clip, clipBoxes);
|
|
nvidiaPaintRegion (screen->pScreen, &pPortPriv->clip, pPortPriv->colorKey);
|
|
}
|
|
|
|
pPortPriv->videoOn = TRUE;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
nvidiaQueryImageAttributes(KdScreenInfo *screen,
|
|
int id,
|
|
unsigned short *w,
|
|
unsigned short *h,
|
|
int *pitches,
|
|
int *offsets)
|
|
{
|
|
int size, tmp;
|
|
|
|
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_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;
|
|
}
|
|
|
|
|
|
/* client libraries expect an encoding */
|
|
static KdVideoEncodingRec DummyEncoding[1] =
|
|
{
|
|
{
|
|
0,
|
|
"XV_IMAGE",
|
|
IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
|
|
{1, 1}
|
|
}
|
|
};
|
|
|
|
#define NUM_FORMATS 3
|
|
|
|
static KdVideoFormatRec Formats[NUM_FORMATS] =
|
|
{
|
|
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
|
|
};
|
|
|
|
#define NUM_ATTRIBUTES 3
|
|
|
|
static KdAttributeRec Attributes[NUM_ATTRIBUTES] =
|
|
{
|
|
{XvSettable | XvGettable, 0, ~0, "XV_COLORKEY"},
|
|
{XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
|
|
{XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}
|
|
};
|
|
|
|
#define NUM_IMAGES 4
|
|
|
|
static KdImageRec Images[NUM_IMAGES] =
|
|
{
|
|
XVIMAGE_YUY2,
|
|
XVIMAGE_YV12,
|
|
XVIMAGE_I420,
|
|
XVIMAGE_UYVY
|
|
};
|
|
|
|
static void nvidiaResetVideo(KdScreenInfo *screen)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
NvidiaPortPrivPtr pPortPriv = nvidias->pAdaptor->pPortPrivates[0].ptr;
|
|
MediaReg *media = nvidiac->media_reg;
|
|
|
|
/*
|
|
* Default to maximum image size in YV12
|
|
*/
|
|
|
|
}
|
|
|
|
static int
|
|
nvidiaReputImage (KdScreenInfo *screen,
|
|
short drw_x,
|
|
short drw_y,
|
|
RegionPtr clipBoxes,
|
|
pointer data)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
NvidiaPortPrivPtr pPortPriv = (NvidiaPortPrivPtr)data;
|
|
BoxPtr pOldExtents = REGION_EXTENTS (pScreen, &pPortPriv->clip);
|
|
BoxPtr pNewExtents = REGION_EXTENTS (pScreen, clipBoxes);
|
|
|
|
if (pOldExtents->x1 == pNewExtents->x1 &&
|
|
pOldExtents->x2 == pNewExtents->x2 &&
|
|
pOldExtents->y1 == pNewExtents->y1 &&
|
|
pOldExtents->y2 == pNewExtents->y2)
|
|
{
|
|
/* update cliplist */
|
|
if (!REGION_EQUAL (screen->pScreen, &pPortPriv->clip, clipBoxes))
|
|
{
|
|
REGION_COPY (screen->pScreen, &pPortPriv->clip, clipBoxes);
|
|
nvidiaPaintRegion (screen->pScreen, &pPortPriv->clip, pPortPriv->colorKey);
|
|
}
|
|
return Success;
|
|
}
|
|
return BadMatch;
|
|
}
|
|
|
|
static KdVideoAdaptorPtr
|
|
nvidiaSetupImageVideo(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
nvidiaCardInfo(pScreenPriv);
|
|
nvidiaScreenInfo(pScreenPriv);
|
|
KdScreenInfo *screen = pScreenPriv->screen;
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
KdVideoAdaptorPtr adapt;
|
|
NvidiaPortPrivPtr pPortPriv;
|
|
|
|
if(!(adapt = xcalloc(1, sizeof(KdVideoAdaptorRec) +
|
|
sizeof(NvidiaPortPrivRec) +
|
|
sizeof(DevUnion))))
|
|
return NULL;
|
|
|
|
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
|
|
adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
|
|
adapt->name = "Nvidia Video Overlay";
|
|
adapt->nEncodings = 1;
|
|
adapt->pEncodings = DummyEncoding;
|
|
adapt->nFormats = NUM_FORMATS;
|
|
adapt->pFormats = Formats;
|
|
adapt->nPorts = 1;
|
|
adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
|
|
|
|
pPortPriv = (NvidiaPortPrivPtr)(&adapt->pPortPrivates[1]);
|
|
|
|
adapt->pPortPrivates[0].ptr = (pointer)(pPortPriv);
|
|
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 = nvidiaStopVideo;
|
|
adapt->SetPortAttribute = nvidiaSetPortAttribute;
|
|
adapt->GetPortAttribute = nvidiaGetPortAttribute;
|
|
adapt->QueryBestSize = nvidiaQueryBestSize;
|
|
adapt->PutImage = nvidiaPutImage;
|
|
adapt->ReputImage = nvidiaReputImage;
|
|
adapt->QueryImageAttributes = nvidiaQueryImageAttributes;
|
|
|
|
pPortPriv->colorKey = nvidias->colorKey;
|
|
pPortPriv->videoOn = FALSE;
|
|
pPortPriv->brightness = 0;
|
|
pPortPriv->saturation = 0;
|
|
pPortPriv->currentBuf = 0;
|
|
|
|
/* gotta uninit this someplace */
|
|
REGION_INIT(pScreen, &pPortPriv->clip, NullBox, 0);
|
|
|
|
nvidias->pAdaptor = adapt;
|
|
|
|
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
|
|
xvSaturation = MAKE_ATOM("XV_SATURATION");
|
|
xvColorKey = MAKE_ATOM("XV_COLORKEY");
|
|
|
|
nvidiaResetVideo(screen);
|
|
|
|
return adapt;
|
|
}
|
|
|
|
Bool nvidiaInitVideo(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
KdScreenInfo *screen = pScreenPriv->screen;
|
|
KdVideoAdaptorPtr *adaptors, *newAdaptors = NULL;
|
|
KdVideoAdaptorPtr newAdaptor = NULL;
|
|
int num_adaptors;
|
|
KdCardInfo *card = pScreenPriv->card;
|
|
NvidiaScreenInfo *nvidias = (NvidiaScreenInfo *) screen->driver;
|
|
NvidiaCardInfo *nvidiac = (NvidiaCardInfo *) card->driver;
|
|
|
|
if (!nvidiac->media_reg)
|
|
return FALSE;
|
|
|
|
newAdaptor = nvidiaSetupImageVideo(pScreen);
|
|
|
|
num_adaptors = KdXVListGenericAdaptors(screen, &adaptors);
|
|
|
|
if(newAdaptor)
|
|
{
|
|
if(!num_adaptors)
|
|
{
|
|
num_adaptors = 1;
|
|
adaptors = &newAdaptor;
|
|
}
|
|
else
|
|
{
|
|
newAdaptors = xalloc((num_adaptors + 1) *
|
|
sizeof(KdVideoAdaptorPtr*));
|
|
if(newAdaptors)
|
|
{
|
|
memcpy(newAdaptors, adaptors,
|
|
num_adaptors * sizeof(KdVideoAdaptorPtr));
|
|
newAdaptors[num_adaptors] = newAdaptor;
|
|
adaptors = newAdaptors;
|
|
num_adaptors++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(num_adaptors)
|
|
KdXVScreenInit(pScreen, adaptors, num_adaptors);
|
|
|
|
if(newAdaptors)
|
|
xfree(newAdaptors);
|
|
return TRUE;
|
|
}
|