985 lines
24 KiB
C
985 lines
24 KiB
C
/*
|
|
* Copyright © 2004 Keith Packard
|
|
* Copyright © 2005 Eric Anholt
|
|
*
|
|
* 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 Eric Anholt not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Eric Anholt makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL ERIC ANHOLT 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.
|
|
*
|
|
* Based on mach64video.c by Keith Packard.
|
|
*/
|
|
/* $RCSId$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include "ati.h"
|
|
#include "ati_dma.h"
|
|
#include "ati_draw.h"
|
|
#include "ati_reg.h"
|
|
#include "kaa.h"
|
|
|
|
#include <X11/extensions/Xv.h>
|
|
#include "fourcc.h"
|
|
|
|
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
|
|
|
|
static Atom xvBrightness, xvSaturation;
|
|
|
|
extern CARD8 ATIBltRop[16];
|
|
|
|
#define IMAGE_MAX_WIDTH 2048
|
|
#define IMAGE_MAX_HEIGHT 2048
|
|
|
|
static void
|
|
ATIStopVideo(KdScreenInfo *screen, pointer data, Bool exit)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
ATIPortPrivPtr pPortPriv = (ATIPortPrivPtr)data;
|
|
|
|
REGION_EMPTY(screen->pScreen, &pPortPriv->clip);
|
|
|
|
if (pPortPriv->off_screen) {
|
|
KdOffscreenFree (pScreen, pPortPriv->off_screen);
|
|
pPortPriv->off_screen = 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
ATISetPortAttribute(KdScreenInfo *screen, Atom attribute, int value,
|
|
pointer data)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
|
|
static int
|
|
ATIGetPortAttribute(KdScreenInfo *screen, Atom attribute, int *value,
|
|
pointer data)
|
|
{
|
|
return BadMatch;
|
|
}
|
|
|
|
static void
|
|
ATIQueryBestSize(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;
|
|
}
|
|
|
|
/* ATIClipVideo -
|
|
|
|
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
|
|
ATIClipVideo(BoxPtr dst, INT32 *x1, INT32 *x2, INT32 *y1, INT32 *y2,
|
|
BoxPtr extents, 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
|
|
R128DisplayVideo(KdScreenInfo *screen, ATIPortPrivPtr pPortPriv)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
CARD32 dstDatatype, srcDatatype;
|
|
CARD32 dst_offset, dst_pitch;
|
|
int dstxoff, dstyoff;
|
|
PixmapPtr pPixmap = pPortPriv->pPixmap;
|
|
int bpp = pPixmap->drawable.bitsPerPixel;
|
|
RING_LOCALS;
|
|
|
|
BoxPtr pBox = REGION_RECTS(&pPortPriv->clip);
|
|
int nBox = REGION_NUM_RECTS(&pPortPriv->clip);
|
|
|
|
if (pPortPriv->id == FOURCC_UYVY)
|
|
srcDatatype = R128_DATATYPE_YVYU_422;
|
|
else
|
|
srcDatatype = R128_DATATYPE_VYUY_422;
|
|
|
|
switch (bpp)
|
|
{
|
|
case 16:
|
|
if (pPixmap->drawable.depth == 15)
|
|
dstDatatype = R128_DATATYPE_ARGB1555;
|
|
else
|
|
dstDatatype = R128_DATATYPE_RGB565;
|
|
break;
|
|
case 32:
|
|
dstDatatype = R128_DATATYPE_ARGB8888;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
dst_offset = ((CARD8 *)pPixmap->devPrivate.ptr -
|
|
pScreenPriv->screen->memory_base);
|
|
dst_pitch = pPixmap->devKind;
|
|
#ifdef COMPOSITE
|
|
dstxoff = -pPixmap->screen_x + pPixmap->drawable.x;
|
|
dstyoff = -pPixmap->screen_y + pPixmap->drawable.y;
|
|
#else
|
|
dstxoff = 0;
|
|
dstyoff = 0;
|
|
#endif
|
|
|
|
BEGIN_DMA(18);
|
|
OUT_REG(ATI_REG_DST_PITCH_OFFSET,
|
|
((dst_pitch / bpp) << 21) | (dst_offset >> 5));
|
|
OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL,
|
|
ATI_GMC_DST_PITCH_OFFSET_CNTL |
|
|
ATI_GMC_BRUSH_NONE |
|
|
(dstDatatype << 8) |
|
|
ATI_GMC_SRC_DATATYPE_COLOR |
|
|
(ATIBltRop[GXcopy] << 16) |
|
|
R128_GMC_3D_FCN_EN |
|
|
ATI_GMC_CLR_CMP_CNTL_DIS |
|
|
R128_GMC_AUX_CLIP_DIS);
|
|
OUT_REG(ATI_REG_DP_CNTL,
|
|
ATI_DST_X_LEFT_TO_RIGHT | ATI_DST_Y_TOP_TO_BOTTOM );
|
|
OUT_REG(R128_REG_SCALE_3D_CNTL,
|
|
R128_SCALE_3D_SCALE |
|
|
R128_SBLEND_ONE |
|
|
R128_DBLEND_ZERO);
|
|
OUT_REG(R128_REG_TEX_CNTL_C, R128_TEX_CACHE_FLUSH);
|
|
OUT_REG(R128_REG_SCALE_3D_DATATYPE, srcDatatype);
|
|
|
|
OUT_RING(DMA_PACKET0(R128_REG_SCALE_PITCH, 5));
|
|
OUT_RING_REG(R128_REG_SCALE_PITCH, pPortPriv->src_pitch / 16);
|
|
OUT_RING_REG(R128_REG_SCALE_X_INC,
|
|
(pPortPriv->src_w << 16) / pPortPriv->dst_w);
|
|
OUT_RING_REG(R128_REG_SCALE_Y_INC,
|
|
(pPortPriv->src_h << 16) / pPortPriv->dst_h);
|
|
OUT_RING_REG(R128_REG_SCALE_HACC, 0x0);
|
|
OUT_RING_REG(R128_REG_SCALE_VACC, 0x0);
|
|
|
|
END_DMA();
|
|
|
|
while (nBox--) {
|
|
int srcX, srcY, dstX, dstY, srcw, srch, dstw, dsth;
|
|
|
|
dstX = pBox->x1 + dstxoff;
|
|
dstY = pBox->y1 + dstyoff;
|
|
dstw = pBox->x2 - pBox->x1;
|
|
dsth = pBox->y2 - pBox->y1;
|
|
srcX = (pBox->x1 - pPortPriv->dst_x1) *
|
|
pPortPriv->src_w / pPortPriv->dst_w;
|
|
srcY = (pBox->y1 - pPortPriv->dst_y1) *
|
|
pPortPriv->src_h / pPortPriv->dst_h;
|
|
srcw = pPortPriv->src_w - srcX;
|
|
srch = pPortPriv->src_h - srcY;
|
|
|
|
BEGIN_DMA(6);
|
|
OUT_RING(DMA_PACKET0(R128_REG_SCALE_SRC_HEIGHT_WIDTH, 2));
|
|
OUT_RING_REG(R128_REG_SCALE_SRC_HEIGHT_WIDTH,
|
|
(srch << 16) | srcw);
|
|
OUT_RING_REG(R128_REG_SCALE_OFFSET_0, pPortPriv->src_offset +
|
|
srcY * pPortPriv->src_pitch + srcX * 2);
|
|
|
|
OUT_RING(DMA_PACKET0(R128_REG_SCALE_DST_X_Y, 2));
|
|
OUT_RING_REG(R128_REG_SCALE_DST_X_Y, (dstX << 16) | dstY);
|
|
OUT_RING_REG(R128_REG_SCALE_DST_HEIGHT_WIDTH,
|
|
(dsth << 16) | dstw);
|
|
END_DMA();
|
|
pBox++;
|
|
}
|
|
#ifdef DAMAGEEXT
|
|
/* XXX: Shouldn't this be in kxv.c instead? */
|
|
DamageDamageRegion(pPortPriv->pDraw, &pPortPriv->clip);
|
|
#endif
|
|
kaaMarkSync(pScreen);
|
|
}
|
|
|
|
union intfloat {
|
|
float f;
|
|
CARD32 i;
|
|
};
|
|
|
|
struct blend_vertex {
|
|
union intfloat x, y;
|
|
union intfloat s0, t0;
|
|
};
|
|
|
|
#define VTX_DWORD_COUNT 4
|
|
|
|
#define VTX_OUT(vtx) \
|
|
do { \
|
|
OUT_RING(vtx.x.i); \
|
|
OUT_RING(vtx.y.i); \
|
|
OUT_RING(vtx.s0.i); \
|
|
OUT_RING(vtx.t0.i); \
|
|
} while (0)
|
|
|
|
static void
|
|
RadeonDisplayVideo(KdScreenInfo *screen, ATIPortPrivPtr pPortPriv)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
ATICardInfo(pScreenPriv);
|
|
ATIScreenInfo(pScreenPriv);
|
|
struct blend_vertex vtx[4];
|
|
PixmapPtr pPixmap = pPortPriv->pPixmap;
|
|
CARD32 txformat;
|
|
CARD32 dst_offset, dst_pitch, dst_format;
|
|
int dstxoff, dstyoff, pixel_shift;
|
|
RING_LOCALS;
|
|
|
|
BoxPtr pBox = REGION_RECTS(&pPortPriv->clip);
|
|
int nBox = REGION_NUM_RECTS(&pPortPriv->clip);
|
|
|
|
switch (pPixmap->drawable.bitsPerPixel) {
|
|
case 16:
|
|
if (pPixmap->drawable.depth == 15)
|
|
dst_format = RADEON_COLOR_FORMAT_ARGB1555;
|
|
else
|
|
dst_format = RADEON_COLOR_FORMAT_RGB565;
|
|
pixel_shift = 1;
|
|
break;
|
|
case 32:
|
|
dst_format = RADEON_COLOR_FORMAT_ARGB8888;
|
|
pixel_shift = 2;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
dst_offset = ((CARD8 *)pPixmap->devPrivate.ptr -
|
|
pScreenPriv->screen->memory_base);
|
|
dst_pitch = pPixmap->devKind;
|
|
|
|
#ifdef COMPOSITE
|
|
dstxoff = -pPixmap->screen_x + pPixmap->drawable.x;
|
|
dstyoff = -pPixmap->screen_y + pPixmap->drawable.y;
|
|
#else
|
|
dstxoff = 0;
|
|
dstyoff = 0;
|
|
#endif
|
|
|
|
/* Same for R100/R200 */
|
|
if (pPortPriv->id == FOURCC_UYVY)
|
|
txformat = RADEON_TXFORMAT_YVYU422;
|
|
else
|
|
txformat = RADEON_TXFORMAT_VYUY422;
|
|
|
|
txformat |= RADEON_TXFORMAT_NON_POWER2;
|
|
|
|
RadeonSwitchTo3D(atis);
|
|
|
|
BEGIN_DMA(8);
|
|
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_CNTL, 3));
|
|
OUT_RING_REG(RADEON_REG_PP_CNTL,
|
|
RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE);
|
|
OUT_RING_REG(RADEON_REG_RB3D_CNTL,
|
|
dst_format | RADEON_ALPHA_BLEND_ENABLE);
|
|
OUT_RING_REG(RADEON_REG_RB3D_COLOROFFSET, dst_offset);
|
|
|
|
OUT_REG(RADEON_REG_RB3D_COLORPITCH, dst_pitch >> pixel_shift);
|
|
|
|
OUT_REG(RADEON_REG_RB3D_BLENDCNTL,
|
|
RADEON_SBLEND_GL_ONE | RADEON_DBLEND_GL_ZERO);
|
|
|
|
END_DMA();
|
|
|
|
if (atic->is_r200) {
|
|
BEGIN_DMA(17);
|
|
|
|
OUT_REG(R200_REG_SE_VTX_FMT_0, R200_VTX_XY);
|
|
OUT_REG(R200_REG_SE_VTX_FMT_1,
|
|
(2 << R200_VTX_TEX0_COMP_CNT_SHIFT));
|
|
|
|
OUT_RING(DMA_PACKET0(R200_REG_PP_TXFILTER_0, 5));
|
|
OUT_RING_REG(R200_REG_PP_TXFILTER_0,
|
|
R200_MAG_FILTER_LINEAR |
|
|
R200_MIN_FILTER_LINEAR |
|
|
R200_YUV_TO_RGB);
|
|
OUT_RING_REG(R200_REG_PP_TXFORMAT_0, txformat);
|
|
OUT_RING_REG(R200_REG_PP_TXFORMAT_X_0, 0);
|
|
OUT_RING_REG(R200_REG_PP_TXSIZE_0,
|
|
(pPixmap->drawable.width - 1) |
|
|
((pPixmap->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT));
|
|
OUT_RING_REG(R200_REG_PP_TXPITCH_0, pPortPriv->src_pitch - 32);
|
|
|
|
OUT_REG(R200_PP_TXOFFSET_0, pPortPriv->src_offset);
|
|
|
|
OUT_RING(DMA_PACKET0(R200_REG_PP_TXCBLEND_0, 4));
|
|
OUT_RING_REG(R200_REG_PP_TXCBLEND_0,
|
|
R200_TXC_ARG_A_ZERO |
|
|
R200_TXC_ARG_B_ZERO |
|
|
R200_TXC_ARG_C_R0_COLOR |
|
|
R200_TXC_OP_MADD);
|
|
OUT_RING_REG(R200_REG_PP_TXCBLEND2_0,
|
|
R200_TXC_CLAMP_0_1 | R200_TXC_OUTPUT_REG_R0);
|
|
OUT_RING_REG(R200_REG_PP_TXABLEND_0,
|
|
R200_TXA_ARG_A_ZERO |
|
|
R200_TXA_ARG_B_ZERO |
|
|
R200_TXA_ARG_C_R0_ALPHA |
|
|
R200_TXA_OP_MADD);
|
|
OUT_RING_REG(R200_REG_PP_TXABLEND2_0,
|
|
R200_TXA_CLAMP_0_1 | R200_TXA_OUTPUT_REG_R0);
|
|
|
|
END_DMA();
|
|
} else {
|
|
BEGIN_DMA(9);
|
|
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TXFILTER_0, 5));
|
|
OUT_RING_REG(RADEON_REG_PP_TXFILTER_0, RADEON_MAG_FILTER_LINEAR |
|
|
RADEON_MIN_FILTER_LINEAR |
|
|
RADEON_YUV_TO_RGB);
|
|
OUT_RING_REG(RADEON_REG_PP_TXFORMAT_0, txformat);
|
|
OUT_RING_REG(RADEON_REG_PP_TXOFFSET_0, pPortPriv->src_offset);
|
|
OUT_RING_REG(RADEON_REG_PP_TXCBLEND_0,
|
|
RADEON_COLOR_ARG_A_ZERO |
|
|
RADEON_COLOR_ARG_B_ZERO |
|
|
RADEON_COLOR_ARG_C_T0_COLOR |
|
|
RADEON_BLEND_CTL_ADD |
|
|
RADEON_CLAMP_TX);
|
|
OUT_RING_REG(RADEON_REG_PP_TXABLEND_0,
|
|
RADEON_ALPHA_ARG_A_ZERO |
|
|
RADEON_ALPHA_ARG_B_ZERO |
|
|
RADEON_ALPHA_ARG_C_T0_ALPHA |
|
|
RADEON_BLEND_CTL_ADD |
|
|
RADEON_CLAMP_TX);
|
|
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TEX_SIZE_0, 2));
|
|
OUT_RING_REG(RADEON_REG_PP_TEX_SIZE_0,
|
|
(pPixmap->drawable.width - 1) |
|
|
((pPixmap->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT));
|
|
OUT_RING_REG(RADEON_REG_PP_TEX_PITCH_0,
|
|
pPortPriv->src_pitch - 32);
|
|
|
|
END_DMA();
|
|
}
|
|
|
|
while (nBox--) {
|
|
float srcX, srcY, dstX, dstY, srcw, srch, dstw, dsth;
|
|
|
|
dstX = pBox->x1 + dstxoff;
|
|
dstY = pBox->y1 + dstyoff;
|
|
dstw = pBox->x2 - pBox->x1;
|
|
dsth = pBox->y2 - pBox->y1;
|
|
srcX = (pBox->x1 - pPortPriv->dst_x1) *
|
|
pPortPriv->src_w / pPortPriv->dst_w;
|
|
srcY = (pBox->y1 - pPortPriv->dst_y1) *
|
|
pPortPriv->src_h / pPortPriv->dst_h;
|
|
srcw = pPortPriv->src_w * (dstw / pPortPriv->dst_w);
|
|
srch = pPortPriv->src_h * (dsth / pPortPriv->dst_h);
|
|
|
|
vtx[0].x.f = dstX;
|
|
vtx[0].y.f = dstY;
|
|
vtx[0].s0.f = srcX;
|
|
vtx[0].t0.f = srcY;
|
|
|
|
vtx[1].x.f = dstX;
|
|
vtx[1].y.f = dstY + dsth;
|
|
vtx[1].s0.f = srcX;
|
|
vtx[1].t0.f = srcY + srch;
|
|
|
|
vtx[2].x.f = dstX + dstw;
|
|
vtx[2].y.f = dstY + dsth;
|
|
vtx[2].s0.f = srcX + srcw;
|
|
vtx[2].t0.f = srcY + srch;
|
|
|
|
vtx[3].x.f = dstX + dstw;
|
|
vtx[3].y.f = dstY;
|
|
vtx[3].s0.f = srcX + srcw;
|
|
vtx[3].t0.f = srcY;
|
|
|
|
if (atic->is_r100) {
|
|
BEGIN_DMA(4 * VTX_DWORD_COUNT + 3);
|
|
OUT_RING(DMA_PACKET3(RADEON_CP_PACKET3_3D_DRAW_IMMD,
|
|
4 * VTX_DWORD_COUNT + 2));
|
|
OUT_RING(RADEON_CP_VC_FRMT_XY |
|
|
RADEON_CP_VC_FRMT_ST0);
|
|
OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN |
|
|
RADEON_CP_VC_CNTL_PRIM_WALK_RING |
|
|
RADEON_CP_VC_CNTL_MAOS_ENABLE |
|
|
RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE |
|
|
(4 << RADEON_CP_VC_CNTL_NUM_SHIFT));
|
|
} else {
|
|
BEGIN_DMA(4 * VTX_DWORD_COUNT + 2);
|
|
OUT_RING(DMA_PACKET3(R200_CP_PACKET3_3D_DRAW_IMMD_2,
|
|
4 * VTX_DWORD_COUNT + 1));
|
|
OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN |
|
|
RADEON_CP_VC_CNTL_PRIM_WALK_RING |
|
|
(4 << RADEON_CP_VC_CNTL_NUM_SHIFT));
|
|
}
|
|
|
|
VTX_OUT(vtx[0]);
|
|
VTX_OUT(vtx[1]);
|
|
VTX_OUT(vtx[2]);
|
|
VTX_OUT(vtx[3]);
|
|
|
|
END_DMA();
|
|
|
|
pBox++;
|
|
}
|
|
#ifdef DAMAGEEXT
|
|
/* XXX: Shouldn't this be in kxv.c instead? */
|
|
DamageDamageRegion(pPortPriv->pDraw, &pPortPriv->clip);
|
|
#endif
|
|
kaaMarkSync(pScreen);
|
|
}
|
|
|
|
static void
|
|
ATIVideoSave(ScreenPtr pScreen, KdOffscreenArea *area)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATIPortPrivPtr pPortPriv = atis->pAdaptor->pPortPrivates[0].ptr;
|
|
|
|
if (pPortPriv->off_screen == area)
|
|
pPortPriv->off_screen = 0;
|
|
}
|
|
|
|
static int
|
|
ATIPutImage(KdScreenInfo *screen, DrawablePtr pDraw,
|
|
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)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
ATICardInfo(pScreenPriv);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATIPortPrivPtr pPortPriv = (ATIPortPrivPtr)data;
|
|
char *mmio = atic->reg_base;
|
|
INT32 x1, x2, y1, y2;
|
|
int randr = RR_Rotate_0 /* XXX */;
|
|
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;
|
|
|
|
ATIClipVideo(&dstBox, &x1, &x2, &y1, &y2,
|
|
REGION_EXTENTS(pScreen, clipBoxes), width, height);
|
|
|
|
src_w = (x2 - x1) >> 16;
|
|
src_h = (y2 - y1) >> 16;
|
|
drw_w = dstBox.x2 - dstBox.x1;
|
|
drw_h = dstBox.y2 - dstBox.y1;
|
|
|
|
if ((x1 >= x2) || (y1 >= y2))
|
|
return Success;
|
|
|
|
if (mmio == NULL)
|
|
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:
|
|
default:
|
|
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 * dst_height;
|
|
break;
|
|
case FOURCC_UYVY:
|
|
case FOURCC_YUY2:
|
|
default:
|
|
dstPitch = ((dst_width << 1) + 15) & ~15;
|
|
srcPitch = (width << 1);
|
|
srcPitch2 = 0;
|
|
size = dstPitch * dst_height;
|
|
break;
|
|
}
|
|
|
|
if (pPortPriv->off_screen != NULL && size != pPortPriv->size) {
|
|
KdOffscreenFree(screen->pScreen, pPortPriv->off_screen);
|
|
pPortPriv->off_screen = 0;
|
|
}
|
|
|
|
if (pPortPriv->off_screen == NULL) {
|
|
pPortPriv->off_screen = KdOffscreenAlloc(screen->pScreen,
|
|
size * 2, 64, TRUE, ATIVideoSave, pPortPriv);
|
|
if (pPortPriv->off_screen == NULL)
|
|
return BadAlloc;
|
|
}
|
|
|
|
|
|
if (pDraw->type == DRAWABLE_WINDOW)
|
|
pPortPriv->pPixmap =
|
|
(*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
|
|
else
|
|
pPortPriv->pPixmap = (PixmapPtr)pDraw;
|
|
|
|
/* Migrate the pixmap to offscreen if necessary. */
|
|
if (!kaaPixmapIsOffscreen(pPortPriv->pPixmap))
|
|
kaaMoveInPixmap(pPortPriv->pPixmap);
|
|
|
|
if (!kaaPixmapIsOffscreen(pPortPriv->pPixmap)) {
|
|
return BadAlloc;
|
|
}
|
|
|
|
pPortPriv->src_offset = pPortPriv->off_screen->offset;
|
|
pPortPriv->src_addr = (CARD8 *)(pScreenPriv->screen->memory_base +
|
|
pPortPriv->src_offset);
|
|
pPortPriv->src_pitch = dstPitch;
|
|
pPortPriv->size = size;
|
|
pPortPriv->pDraw = pDraw;
|
|
|
|
/* copy data */
|
|
top = rot_y1 >> 16;
|
|
left = (rot_x1 >> 16) & ~1;
|
|
npixels = ((((rot_x2 + 0xffff) >> 16) + 1) & ~1) - left;
|
|
|
|
/* Since we're probably overwriting the area that might still be used
|
|
* for the last PutImage request, wait for idle.
|
|
*/
|
|
ATIWaitIdle(atis);
|
|
|
|
switch(id) {
|
|
case FOURCC_YV12:
|
|
case FOURCC_I420:
|
|
top &= ~1;
|
|
nlines = ((((rot_y2 + 0xffff) >> 16) + 1) & ~1) - top;
|
|
KdXVCopyPlanarData(screen, buf, pPortPriv->src_addr, 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;
|
|
KdXVCopyPackedData(screen, buf, pPortPriv->src_addr, randr,
|
|
srcPitch, dstPitch, rot_src_w, rot_src_h, top, left,
|
|
nlines, npixels);
|
|
break;
|
|
}
|
|
|
|
/* update cliplist */
|
|
if (!REGION_EQUAL(screen->pScreen, &pPortPriv->clip, clipBoxes)) {
|
|
REGION_COPY(screen->pScreen, &pPortPriv->clip, clipBoxes);
|
|
}
|
|
|
|
pPortPriv->id = id;
|
|
pPortPriv->src_x1 = rot_x1;
|
|
pPortPriv->src_y1 = rot_y1;
|
|
pPortPriv->src_x2 = rot_x2;
|
|
pPortPriv->src_y2 = rot_y2;
|
|
pPortPriv->src_w = rot_src_w;
|
|
pPortPriv->src_h = rot_src_h;
|
|
pPortPriv->dst_x1 = dst_x1;
|
|
pPortPriv->dst_y1 = dst_y1;
|
|
pPortPriv->dst_x2 = dst_x2;
|
|
pPortPriv->dst_y2 = dst_y2;
|
|
pPortPriv->dst_w = rot_drw_w;
|
|
pPortPriv->dst_h = rot_drw_h;
|
|
|
|
if (atic->is_radeon)
|
|
RadeonDisplayVideo(screen, pPortPriv);
|
|
else
|
|
R128DisplayVideo(screen, pPortPriv);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ATIReputImage(KdScreenInfo *screen, DrawablePtr pDraw, short drw_x, short drw_y,
|
|
RegionPtr clipBoxes, pointer data)
|
|
{
|
|
ScreenPtr pScreen = screen->pScreen;
|
|
KdScreenPriv(pScreen);
|
|
ATICardInfo(pScreenPriv);
|
|
ATIPortPrivPtr pPortPriv = (ATIPortPrivPtr)data;
|
|
BoxPtr pOldExtents = REGION_EXTENTS(screen->pScreen, &pPortPriv->clip);
|
|
BoxPtr pNewExtents = REGION_EXTENTS(screen->pScreen, clipBoxes);
|
|
|
|
if (pOldExtents->x1 != pNewExtents->x1 ||
|
|
pOldExtents->x2 != pNewExtents->x2 ||
|
|
pOldExtents->y1 != pNewExtents->y1 ||
|
|
pOldExtents->y2 != pNewExtents->y2)
|
|
return BadMatch;
|
|
|
|
if (pDraw->type == DRAWABLE_WINDOW)
|
|
pPortPriv->pPixmap =
|
|
(*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
|
|
else
|
|
pPortPriv->pPixmap = (PixmapPtr)pDraw;
|
|
|
|
if (!kaaPixmapIsOffscreen(pPortPriv->pPixmap))
|
|
kaaMoveInPixmap(pPortPriv->pPixmap);
|
|
|
|
if (!kaaPixmapIsOffscreen(pPortPriv->pPixmap)) {
|
|
ErrorF("err\n");
|
|
return BadAlloc;
|
|
}
|
|
|
|
|
|
/* update cliplist */
|
|
if (!REGION_EQUAL(screen->pScreen, &pPortPriv->clip, clipBoxes))
|
|
REGION_COPY(screen->pScreen, &pPortPriv->clip, clipBoxes);
|
|
|
|
/* XXX: What do the drw_x and drw_y here mean for us? */
|
|
|
|
if (atic->is_radeon)
|
|
RadeonDisplayVideo(screen, pPortPriv);
|
|
else
|
|
R128DisplayVideo(screen, pPortPriv);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ATIQueryImageAttributes(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 0
|
|
|
|
static KdAttributeRec Attributes[NUM_ATTRIBUTES] =
|
|
{
|
|
};
|
|
|
|
#define NUM_IMAGES 4
|
|
|
|
static KdImageRec Images[NUM_IMAGES] =
|
|
{
|
|
XVIMAGE_YUY2,
|
|
XVIMAGE_YV12,
|
|
XVIMAGE_I420,
|
|
XVIMAGE_UYVY
|
|
};
|
|
|
|
static KdVideoAdaptorPtr
|
|
ATISetupImageVideo(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
KdVideoAdaptorPtr adapt;
|
|
ATIPortPrivPtr pPortPriv;
|
|
int i;
|
|
|
|
atis->num_texture_ports = 16;
|
|
|
|
adapt = xcalloc(1, sizeof(KdVideoAdaptorRec) + atis->num_texture_ports *
|
|
(sizeof(ATIPortPrivRec) + sizeof(DevUnion)));
|
|
if (adapt == NULL)
|
|
return NULL;
|
|
|
|
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
|
|
adapt->flags = VIDEO_CLIP_TO_VIEWPORT;
|
|
adapt->name = "ATI Texture Video";
|
|
adapt->nEncodings = 1;
|
|
adapt->pEncodings = DummyEncoding;
|
|
adapt->nFormats = NUM_FORMATS;
|
|
adapt->pFormats = Formats;
|
|
adapt->nPorts = atis->num_texture_ports;
|
|
adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
|
|
|
|
pPortPriv =
|
|
(ATIPortPrivPtr)(&adapt->pPortPrivates[atis->num_texture_ports]);
|
|
|
|
for (i = 0; i < atis->num_texture_ports; i++)
|
|
adapt->pPortPrivates[i].ptr = &pPortPriv[i];
|
|
|
|
adapt->nAttributes = NUM_ATTRIBUTES;
|
|
adapt->pAttributes = Attributes;
|
|
adapt->pImages = Images;
|
|
adapt->nImages = NUM_IMAGES;
|
|
adapt->PutVideo = NULL;
|
|
adapt->PutStill = NULL;
|
|
adapt->GetVideo = NULL;
|
|
adapt->GetStill = NULL;
|
|
adapt->StopVideo = ATIStopVideo;
|
|
adapt->SetPortAttribute = ATISetPortAttribute;
|
|
adapt->GetPortAttribute = ATIGetPortAttribute;
|
|
adapt->QueryBestSize = ATIQueryBestSize;
|
|
adapt->PutImage = ATIPutImage;
|
|
adapt->ReputImage = ATIReputImage;
|
|
adapt->QueryImageAttributes = ATIQueryImageAttributes;
|
|
|
|
/* gotta uninit this someplace */
|
|
REGION_INIT(pScreen, &pPortPriv->clip, NullBox, 0);
|
|
|
|
atis->pAdaptor = adapt;
|
|
|
|
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
|
|
xvSaturation = MAKE_ATOM("XV_SATURATION");
|
|
|
|
return adapt;
|
|
}
|
|
|
|
Bool ATIInitVideo(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
KdScreenInfo *screen = pScreenPriv->screen;
|
|
KdVideoAdaptorPtr *adaptors, *newAdaptors = NULL;
|
|
KdVideoAdaptorPtr newAdaptor = NULL;
|
|
int num_adaptors;
|
|
|
|
atis->pAdaptor = NULL;
|
|
|
|
if (atic->reg_base == NULL)
|
|
return FALSE;
|
|
if (atic->is_r300)
|
|
return FALSE;
|
|
|
|
num_adaptors = KdXVListGenericAdaptors(screen, &adaptors);
|
|
|
|
newAdaptor = ATISetupImageVideo(pScreen);
|
|
|
|
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;
|
|
}
|
|
|
|
void
|
|
ATIFiniVideo(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
KdVideoAdaptorPtr adapt = atis->pAdaptor;
|
|
ATIPortPrivPtr pPortPriv;
|
|
int i;
|
|
|
|
if (!adapt)
|
|
return;
|
|
|
|
for (i = 0; i < atis->num_texture_ports; i++) {
|
|
pPortPriv = (ATIPortPrivPtr)(&adapt->pPortPrivates[i].ptr);
|
|
REGION_UNINIT(pScreen, &pPortPriv->clip);
|
|
}
|
|
xfree(adapt);
|
|
atis->pAdaptor = NULL;
|
|
}
|