aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/kdrive/ati/ati_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/kdrive/ati/ati_video.c')
-rw-r--r--xorg-server/hw/kdrive/ati/ati_video.c988
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;
+}