diff options
Diffstat (limited to 'xorg-server/hw/kdrive/ati/ati_video.c')
-rw-r--r-- | xorg-server/hw/kdrive/ati/ati_video.c | 988 |
1 files changed, 988 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/ati/ati_video.c b/xorg-server/hw/kdrive/ati/ati_video.c new file mode 100644 index 000000000..ca0ab464a --- /dev/null +++ b/xorg-server/hw/kdrive/ati/ati_video.c @@ -0,0 +1,988 @@ +/* + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-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(11); + 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); + +// OUT_RING_REG(ATI_REG_WAIT_UNTIL, ATI_WAIT_CRTC_VLINE); + + 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); + + /* + * rectangle: + * + * +---------2 + * | | + * | | + * 0---------1 + */ + + vtx[0].x.f = dstX; + vtx[0].y.f = dstY + dsth; + vtx[0].s0.f = srcX; + vtx[0].t0.f = srcY + srch; + + vtx[1].x.f = dstX + dstw; + vtx[1].y.f = dstY + dsth; + vtx[1].s0.f = srcX + srcw; + vtx[1].t0.f = srcY + srch; + + vtx[2].x.f = dstX + dstw; + vtx[2].y.f = dstY; + vtx[2].s0.f = srcX + srcw; + vtx[2].t0.f = srcY; + + if (atic->is_r100) { + BEGIN_DMA(3 * VTX_DWORD_COUNT + 3); + OUT_RING(DMA_PACKET3(RADEON_CP_PACKET3_3D_DRAW_IMMD, + 3 * VTX_DWORD_COUNT + 2)); + OUT_RING(RADEON_CP_VC_FRMT_XY | + RADEON_CP_VC_FRMT_ST0); + OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST | + RADEON_CP_VC_CNTL_PRIM_WALK_RING | + RADEON_CP_VC_CNTL_MAOS_ENABLE | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE | + (3 << RADEON_CP_VC_CNTL_NUM_SHIFT)); + } else { + BEGIN_DMA(3 * VTX_DWORD_COUNT + 2); + OUT_RING(DMA_PACKET3(R200_CP_PACKET3_3D_DRAW_IMMD_2, + 3 * VTX_DWORD_COUNT + 1)); + OUT_RING(RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST | + RADEON_CP_VC_CNTL_PRIM_WALK_RING | + (3 << RADEON_CP_VC_CNTL_NUM_SHIFT)); + } + + VTX_OUT(vtx[0]); + VTX_OUT(vtx[1]); + VTX_OUT(vtx[2]); + 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; +} |