cade317d31
- Add monochrome hardware cursor support. - Try to auto-detect AGP support for DRI on Radeons. And fail. Detect it properly on R128. - Set up card for pseudo-DMA if possible. Convert 2D rendering code to prepare DMA packets only. Use generic code to decode DMA packets to MMIO if PDMA is unavailable. Add WIP code to support "real" DMA without DRM support. - Dispatch pending DMA commands when the server sleeps. Otherwise some things, such as typing in an xterm, wouldn't show up for a time. - Fix Radeon Composite acceleration in many ways, and add Rage 128 Composite acceleration. Disable them both due to still-not-understood issues they have. They fail with In, Out, AtopReverse, and Xor, and text rendering is strange. - Add textured XV support for R100 and Rage 128. No brightness/sat controls, but it does support multiple ports, and cooperates with Composite. - Add WIP code for hostdata uploads. - Many cleanups and fixes.
951 lines
23 KiB
C
951 lines
23 KiB
C
/*
|
|
* Copyright © 2004 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 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(pPortPriv->src_pitch / 16);
|
|
OUT_RING((pPortPriv->src_w << 16) / pPortPriv->dst_w);
|
|
OUT_RING((pPortPriv->src_h << 16) / pPortPriv->dst_h);
|
|
OUT_RING(0x0);
|
|
OUT_RING(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);
|
|
/* R128_REG_SCALE_SRC_HEIGHT_WIDTH,
|
|
* R128_REG_SCALE_OFFSET_0
|
|
*/
|
|
OUT_RING(DMA_PACKET0(R128_REG_SCALE_SRC_HEIGHT_WIDTH, 2));
|
|
OUT_RING((srch << 16) | srcw);
|
|
OUT_RING(pPortPriv->src_offset + srcY * pPortPriv->src_pitch +
|
|
srcX * 2);
|
|
/* R128_REG_SCALE_DST_X_Y
|
|
* R128_REG_SCALE_DST_HEIGHT_WIDTH
|
|
*/
|
|
OUT_RING(DMA_PACKET0(R128_REG_SCALE_DST_X_Y, 2));
|
|
OUT_RING((dstX << 16) | dstY);
|
|
OUT_RING((dsth << 16) | dstw);
|
|
END_DMA();
|
|
pBox++;
|
|
}
|
|
#ifdef DAMAGEEXT
|
|
/* XXX: Shouldn't this be in kxv.c instead? */
|
|
DamageDamageRegion(pPortPriv->pDraw, &pPortPriv->clip);
|
|
#endif
|
|
KdMarkSync(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
|
|
|
|
if (pPortPriv->id == FOURCC_UYVY)
|
|
txformat = RADEON_TXFORMAT_YVYU422;
|
|
else
|
|
txformat = RADEON_TXFORMAT_VYUY422;
|
|
|
|
txformat |= RADEON_TXFORMAT_NON_POWER2;
|
|
|
|
/* RADEON_REG_PP_TXFILTER_0,
|
|
* RADEON_REG_PP_TXFORMAT_0,
|
|
* RADEON_REG_PP_TXOFFSET_0
|
|
*/
|
|
BEGIN_DMA(4);
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TXFILTER_0, 3));
|
|
OUT_RING(RADEON_YUV_TO_RGB);
|
|
OUT_RING(txformat);
|
|
OUT_RING(pPortPriv->src_offset);
|
|
END_DMA();
|
|
|
|
/* RADEON_REG_PP_TEX_SIZE_0,
|
|
* RADEON_REG_PP_TEX_PITCH_0
|
|
*/
|
|
BEGIN_DMA(3);
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TEX_SIZE_0, 2));
|
|
OUT_RING((pPixmap->drawable.width - 1) |
|
|
((pPixmap->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT));
|
|
OUT_RING(pPortPriv->src_pitch - 32);
|
|
END_DMA();
|
|
|
|
BEGIN_DMA(14);
|
|
OUT_REG(ATI_REG_WAIT_UNTIL,
|
|
RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
|
|
|
|
/* RADEON_REG_PP_CNTL,
|
|
* RADEON_REG_RB3D_CNTL,
|
|
* RADEON_REG_RB3D_COLOROFFSET
|
|
*/
|
|
OUT_RING(DMA_PACKET0(RADEON_REG_PP_CNTL, 3));
|
|
OUT_RING(RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE);
|
|
OUT_RING(dst_format | RADEON_ALPHA_BLEND_ENABLE);
|
|
OUT_RING(dst_offset);
|
|
|
|
OUT_REG(RADEON_REG_RB3D_COLORPITCH, dst_pitch >> pixel_shift);
|
|
|
|
OUT_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_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_REG(RADEON_REG_RB3D_BLENDCNTL,
|
|
RADEON_SBLEND_GL_ONE | RADEON_DBLEND_GL_ZERO);
|
|
|
|
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
|
|
KdMarkSync(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_r200 || 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;
|
|
}
|