Overhaul of the ATI driver:

- 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.
This commit is contained in:
Eric Anholt 2004-05-17 20:18:02 +00:00
parent 834537e212
commit cade317d31
14 changed files with 6557 additions and 1116 deletions

View File

@ -9,7 +9,6 @@ DRI_SOURCES = ati_dri.c \
r128_common.h \
r128_sarea.h \
radeon_common.h \
radeon_composite.c \
radeon_sarea.h
endif
@ -39,13 +38,18 @@ endif
noinst_LIBRARIES = libati.a
libati_a_SOURCES = \
ati_cursor.c \
ati_dma.c \
ati_dma.h \
ati_draw.c \
ati_draw.h \
ati_drawtmp.h \
ati_microcode.c \
ati.c \
ati.h \
ati_reg.h \
r128_blendtmp.h \
r128_composite.c \
ati_video.c \
radeon_composite.c \
$(DRI_SOURCES)
Xati_SOURCES = \

View File

@ -32,10 +32,16 @@
#include "ati_sarea.h"
#endif
#define CAP_R128 0x1 /* If it's a Rage 128 */
#define CAP_R100 0x2 /* If it's an r100 series radeon. */
#define CAP_R200 0x3 /* If it's an r200 series radeon. */
#define CAP_R300 0x4 /* If it's an r300 series radeon. */
static Bool ATIIsAGP(ATICardInfo *atic);
#define CAP_SERIESMASK 0xf
#define CAP_R128 0x1 /* If it's a Rage 128 */
#define CAP_R100 0x2 /* If it's an r100 series radeon. */
#define CAP_R200 0x3 /* If it's an r200 series radeon. */
#define CAP_R300 0x4 /* If it's an r300 series radeon. */
#define CAP_FEATURESMASK 0xf0
#define CAP_NOAGP 0x10 /* If it's a PCI-only card. */
struct pci_id_entry ati_pci_ids[] = {
{0x1002, 0x4136, 0x2, "ATI Radeon RS100"},
@ -63,13 +69,13 @@ struct pci_id_entry ati_pci_ids[] = {
{0x1002, 0x4964, 0x2, "ATI Radeon RV250 Id"},
{0x1002, 0x4965, 0x2, "ATI Radeon RV250 Ie"},
{0x1002, 0x4966, 0x2, "ATI Radeon RV250 If"},
{0x1002, 0x4967, 0x2, "ATI Radeon RV250 Ig"},
{0x1002, 0x4c45, 0x1, "ATI Rage 128 LE"},
{0x1002, 0x4967, 0x2, "ATI Radeon R250 Ig"},
{0x1002, 0x4c45, 0x11, "ATI Rage 128 LE"},
{0x1002, 0x4c46, 0x1, "ATI Rage 128 LF"},
{0x1002, 0x4c57, 0x2, "ATI Radeon RV200 LW"},
{0x1002, 0x4c58, 0x2, "ATI Radeon RV200 LX"},
{0x1002, 0x4c57, 0x2, "ATI Radeon Mobiliy M7 RV200 LW (7500)"},
{0x1002, 0x4c58, 0x2, "ATI Radeon Mobiliy M7 RV200 LX (7500)"},
{0x1002, 0x4c59, 0x2, "ATI Radeon Mobility M6 LY"},
{0x1002, 0x4c5a, 0x2, "ATI Radeon Mobility LZ"},
{0x1002, 0x4c5a, 0x2, "ATI Radeon Mobility M6 LZ"},
{0x1002, 0x4c64, 0x3, "ATI Radeon RV250 Ld"},
{0x1002, 0x4c65, 0x3, "ATI Radeon RV250 Le"},
{0x1002, 0x4c66, 0x3, "ATI Radeon Mobility M9 RV250 Lf"},
@ -93,7 +99,7 @@ struct pci_id_entry ati_pci_ids[] = {
{0x1002, 0x5041, 0x1, "ATI Rage 128 PA"},
{0x1002, 0x5042, 0x1, "ATI Rage 128 PB"},
{0x1002, 0x5043, 0x1, "ATI Rage 128 PC"},
{0x1002, 0x5044, 0x1, "ATI Rage 128 PD"},
{0x1002, 0x5044, 0x11, "ATI Rage 128 PD"},
{0x1002, 0x5045, 0x1, "ATI Rage 128 PE"},
{0x1002, 0x5046, 0x1, "ATI Rage 128 PF"},
{0x1002, 0x5047, 0x1, "ATI Rage 128 PG"},
@ -105,9 +111,9 @@ struct pci_id_entry ati_pci_ids[] = {
{0x1002, 0x504d, 0x1, "ATI Rage 128 PM"},
{0x1002, 0x504e, 0x1, "ATI Rage 128 PN"},
{0x1002, 0x504f, 0x1, "ATI Rage 128 PO"},
{0x1002, 0x5050, 0x1, "ATI Rage 128 PP"},
{0x1002, 0x5050, 0x11, "ATI Rage 128 PP"},
{0x1002, 0x5051, 0x1, "ATI Rage 128 PQ"},
{0x1002, 0x5052, 0x1, "ATI Rage 128 PR"},
{0x1002, 0x5052, 0x11, "ATI Rage 128 PR"},
{0x1002, 0x5053, 0x1, "ATI Rage 128 PS"},
{0x1002, 0x5054, 0x1, "ATI Rage 128 PT"},
{0x1002, 0x5055, 0x1, "ATI Rage 128 PU"},
@ -121,14 +127,14 @@ struct pci_id_entry ati_pci_ids[] = {
{0x1002, 0x5148, 0x3, "ATI Radeon R200 QH"},
{0x1002, 0x514c, 0x3, "ATI Radeon R200 QL"},
{0x1002, 0x514d, 0x3, "ATI Radeon R200 QM"},
{0x1002, 0x5157, 0x2, "ATI Radeon RV200 QW"},
{0x1002, 0x5158, 0x2, "ATI Radeon RV200 QX"},
{0x1002, 0x5157, 0x2, "ATI Radeon RV200 QW (7500)"},
{0x1002, 0x5158, 0x2, "ATI Radeon RV200 QX (7500)"},
{0x1002, 0x5159, 0x2, "ATI Radeon RV100 QY"},
{0x1002, 0x515a, 0x2, "ATI Radeon RV100 QZ"},
{0x1002, 0x5245, 0x1, "ATI Rage 128 RE"},
{0x1002, 0x5245, 0x11, "ATI Rage 128 RE"},
{0x1002, 0x5246, 0x1, "ATI Rage 128 RF"},
{0x1002, 0x5247, 0x1, "ATI Rage 128 RG"},
{0x1002, 0x524b, 0x1, "ATI Rage 128 RK"},
{0x1002, 0x524b, 0x11, "ATI Rage 128 RK"},
{0x1002, 0x524c, 0x1, "ATI Rage 128 RL"},
{0x1002, 0x5345, 0x1, "ATI Rage 128 SE"},
{0x1002, 0x5346, 0x1, "ATI Rage 128 SF"},
@ -233,7 +239,7 @@ ATICardInit(KdCardInfo *card)
/* We demand identification by busid, not driver name */
atic->drmFd = drmOpen(NULL, atic->busid);
if (atic->drmFd < 0)
ErrorF("Failed to open DRM. DMA won't be used.\n");
ErrorF("Failed to open DRM, DRI disabled.\n");
#endif /* USE_DRI */
card->driver = atic;
@ -244,17 +250,20 @@ ATICardInit(KdCardInfo *card)
break;
}
}
if (atic->pci_id->caps != CAP_R128)
if ((atic->pci_id->caps & CAP_SERIESMASK) != CAP_R128)
atic->is_radeon = TRUE;
if (atic->pci_id->caps == CAP_R100)
if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R100)
atic->is_r100 = TRUE;
if (atic->pci_id->caps == CAP_R200)
if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R200)
atic->is_r200 = TRUE;
if (atic->pci_id->caps == CAP_R300)
if ((atic->pci_id->caps & CAP_SERIESMASK) == CAP_R300)
atic->is_r300 = TRUE;
ErrorF("Using ATI card: %s at %s\n", atic->pci_id->name, atic->busid);
atic->is_agp = ATIIsAGP(atic);
ErrorF("Using ATI card: %s (%s) at %s\n", atic->pci_id->name,
atic->is_agp ? "AGP" : "PCI", atic->busid);
return TRUE;
}
@ -284,7 +293,7 @@ ATIScreenInit(KdScreenInfo *screen)
return FALSE;
atis->atic = atic;
atis->screen = screen;
screen->driver = atis;
#ifdef KDRIVEFBDEV
@ -313,11 +322,20 @@ ATIScreenInit(KdScreenInfo *screen)
}
screen->off_screen_base = screen_size;
/* Reserve the area for the monochrome cursor. */
if (screen->off_screen_base +
ATI_CURSOR_HEIGHT * ATI_CURSOR_PITCH * 3 <= screen->memory_size) {
atis->cursor.offset = screen->off_screen_base;
screen->off_screen_base += ATI_CURSOR_HEIGHT * ATI_CURSOR_PITCH * 2;
}
#if defined(USE_DRI) && defined(GLXEXT)
/* Reserve a static area for the back buffer the same size as the
* visible screen. XXX: This would be better initialized in ati_dri.c
* when GLX is set up, but I'm not sure when the offscreen memory
* manager gets set up.
* when GLX is set up, but the offscreen memory manager's allocations
* don't last through VT switches, while the kernel's understanding of
* offscreen locations does.
*/
atis->frontOffset = 0;
atis->frontPitch = screen->fb[0].byteStride;
@ -365,11 +383,12 @@ ATIScreenInit(KdScreenInfo *screen)
* Composite operations, because glyphs aren't in real pixmaps and thus
* can't be migrated.
*/
atis->scratch_size = 65536; /* big enough for 128x128@32bpp */
atis->scratch_size = 131072; /* big enough for 128x128@32bpp */
if (screen->off_screen_base + atis->scratch_size <= screen->memory_size)
{
atis->scratch_offset = screen->off_screen_base;
screen->off_screen_base += atis->scratch_size;
atis->scratch_next = atis->scratch_offset;
} else {
atis->scratch_size = 0;
}
@ -383,6 +402,10 @@ ATIScreenFini(KdScreenInfo *screen)
ATIScreenInfo *atis = (ATIScreenInfo *)screen->driver;
ATICardInfo *atic = screen->card->driver;
#ifdef XV
ATIFiniVideo(screen->pScreen);
#endif
atic->backend_funcs.scrfini(screen);
xfree(atis);
screen->driver = 0;
@ -391,13 +414,13 @@ ATIScreenFini(KdScreenInfo *screen)
Bool
ATIMapReg(KdCardInfo *card, ATICardInfo *atic)
{
atic->reg_base = (CARD8 *)KdMapDevice(RADEON_REG_BASE(card),
RADEON_REG_SIZE(card));
atic->reg_base = (CARD8 *)KdMapDevice(ATI_REG_BASE(card),
ATI_REG_SIZE(card));
if (atic->reg_base == NULL)
return FALSE;
KdSetMappedMode(RADEON_REG_BASE(card), RADEON_REG_SIZE(card),
KdSetMappedMode(ATI_REG_BASE(card), ATI_REG_SIZE(card),
KD_MAPPED_MODE_REGISTERS);
return TRUE;
@ -407,9 +430,9 @@ void
ATIUnmapReg(KdCardInfo *card, ATICardInfo *atic)
{
if (atic->reg_base) {
KdResetMappedMode(RADEON_REG_BASE(card), RADEON_REG_SIZE(card),
KdResetMappedMode(ATI_REG_BASE(card), ATI_REG_SIZE(card),
KD_MAPPED_MODE_REGISTERS);
KdUnmapDevice((void *)atic->reg_base, RADEON_REG_SIZE(card));
KdUnmapDevice((void *)atic->reg_base, ATI_REG_SIZE(card));
atic->reg_base = 0;
}
}
@ -420,6 +443,9 @@ ATIInitScreen(ScreenPtr pScreen)
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
#ifdef XV
ATIInitVideo(pScreen);
#endif
return atic->backend_funcs.initScreen(pScreen);
}
@ -525,7 +551,55 @@ ATILog2(int val)
return 1;
for (bits = 0; val != 0; val >>= 1, ++bits)
;
return bits;
return bits - 1;
}
static Bool
ATIIsAGP(ATICardInfo *atic)
{
char *mmio = atic->reg_base;
CARD32 agp_command;
Bool is_agp = FALSE;
if (mmio == NULL)
return FALSE;
if (atic->is_radeon) {
/* XXX: Apparently this doesn't work. Maybe it needs to be done
* through the PCI config aperture then.
*/
agp_command = MMIO_IN32(mmio, RADEON_REG_AGP_COMMAND);
MMIO_OUT32(mmio, RADEON_REG_AGP_COMMAND, agp_command |
RADEON_AGP_ENABLE);
if (MMIO_IN32(mmio, RADEON_REG_AGP_COMMAND) & RADEON_AGP_ENABLE)
is_agp = TRUE;
MMIO_OUT32(mmio, RADEON_REG_AGP_COMMAND, agp_command);
} else {
/* Don't know any way to detect R128 AGP automatically, so
* assume AGP for all cards not marked as PCI-only by XFree86.
*/
if ((atic->pci_id->caps & CAP_FEATURESMASK) != CAP_NOAGP)
is_agp = TRUE;
}
return is_agp;
}
/* This function is required to work around a hardware bug in some (all?)
* revisions of the R300. This workaround should be called after every
* CLOCK_CNTL_INDEX register access. If not, register reads afterward
* may not be correct.
*/
void R300CGWorkaround(ATIScreenInfo *atis) {
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
CARD32 save;
save = MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX);
MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, save & ~(0x3f |
ATI_PLL_WR_EN));
MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX);
MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, save);
}
KdCardFuncs ATIFuncs = {
@ -542,11 +616,11 @@ KdCardFuncs ATIFuncs = {
ATIScreenFini, /* scrfini */
ATICardFini, /* cardfini */
0, /* initCursor */
0, /* enableCursor */
0, /* disableCursor */
0, /* finiCursor */
0, /* recolorCursor */
ATICursorInit, /* initCursor */
ATICursorEnable, /* enableCursor */
ATICursorDisable, /* disableCursor */
ATICursorFini, /* finiCursor */
ATIRecolorCursor, /* recolorCursor */
ATIDrawInit, /* initAccel */
ATIDrawEnable, /* enableAccel */

View File

@ -26,7 +26,9 @@
#ifndef _ATI_H_
#define _ATI_H_
#include "config.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef KDRIVEFBDEV
#include <fbdev.h>
@ -35,6 +37,8 @@
#include <vesa.h>
#endif
#include "kxv.h"
#ifdef XF86DRI
#define USE_DRI
#include "libdrm.h"
@ -46,8 +50,8 @@
#endif
#endif
#define RADEON_REG_BASE(c) ((c)->attr.address[1])
#define RADEON_REG_SIZE(c) (0x4000)
#define ATI_REG_BASE(c) ((c)->attr.address[1])
#define ATI_REG_SIZE(c) (0x4000)
#ifdef __powerpc__
@ -82,6 +86,18 @@ MMIO_IN32(__volatile__ void *base, const unsigned long offset)
#endif
#define MMIO_OUT8(mmio, a, v) (*(VOL8 *)((mmio) + (a)) = (v))
#define MMIO_IN8(mmio, a, v) (*(VOL8 *)((mmio) + (a)))
#define INPLL(mmio, addr) \
(MMIO_OUT8(mmio, ATI_REG_CLOCK_CNTL_INDEX, addr), \
MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_DATA))
#define OUTPLL(mmio, addr, val) do { \
MMIO_OUT8(mmio, ATI_REG_CLOCK_CNTL_INDEX, (addr) | ATI_PLL_WR_EN); \
MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_DATA, val); \
} while (0)
typedef volatile CARD8 VOL8;
typedef volatile CARD16 VOL16;
typedef volatile CARD32 VOL32;
@ -125,6 +141,7 @@ typedef struct _ATICardInfo {
Bool is_r100;
Bool is_r200;
Bool is_r300;
Bool is_agp;
char *busid;
#ifdef USE_DRI
int drmFd;
@ -135,6 +152,48 @@ typedef struct _ATICardInfo {
#define getATICardInfo(kd) ((ATICardInfo *) ((kd)->card->driver))
#define ATICardInfo(kd) ATICardInfo *atic = getATICardInfo(kd)
typedef struct _ATICursor {
int width, height;
int xhot, yhot;
Bool has_cursor;
CursorPtr pCursor;
Pixel source, mask;
KdOffscreenArea *area;
CARD32 offset;
} ATICursor;
typedef struct _ATIPortPriv {
int brightness;
int saturation;
RegionRec clip;
Bool videoOn;
Time offTime;
Time freeTime;
CARD32 size;
KdOffscreenArea *off_screen;
DrawablePtr pDraw;
PixmapPtr pPixmap;
CARD32 src_offset;
CARD32 src_pitch;
CARD8 *src_addr;
int id;
int src_x1, src_y1, src_x2, src_y2;
int dst_x1, dst_y1, dst_x2, dst_y2;
int src_w, src_h, dst_w, dst_h;
} ATIPortPrivRec, *ATIPortPrivPtr;
typedef struct _dmaBuf {
int size;
int used;
void *address;
#ifdef USE_DRI
drmBufPtr drmBuf;
#endif
} dmaBuf;
typedef struct _ATIScreenInfo {
union {
#ifdef KDRIVEFBDEV
@ -145,20 +204,52 @@ typedef struct _ATIScreenInfo {
#endif
} backend_priv;
KaaScreenInfoRec kaa;
ATICardInfo *atic;
KdScreenInfo *screen;
Bool using_dri;
Bool using_dma;
void (*save_blockhandler)(int screen, pointer blockData,
pointer timeout, pointer readmask);
int scratch_offset;
int scratch_size;
int scratch_offset;
int scratch_next;
int scratch_size;
ATICursor cursor;
KdVideoAdaptorPtr pAdaptor;
int num_texture_ports;
Bool using_pio; /* If we use decode DMA packets to MMIO. */
Bool using_pseudo; /* If we use MMIO to submit DMA packets. */
Bool using_dma; /* If we use non-DRI DMA to submit packets. */
Bool using_dri; /* If we use the DRM for DMA. */
Bool using_agp; /* If we are using AGP or not for DMA. */
KdOffscreenArea *dma_space; /* For "DMA" from framebuffer. */
void *agp_addr; /* Mapped AGP aperture */
int agp_size;
int agp_key; /* Key of AGP memory for DMA */
CARD32 *ring_addr; /* Beginning of ring buffer. */
int ring_write; /* Index of write ptr in ring. */
int ring_read; /* Index of read ptr in ring. */
int ring_len;
dmaBuf *indirectBuffer;
int indirectStart;
int mmio_avail;
int cce_pri_size;
int cce_pri_avail;
#ifdef USE_DRI
Bool dma_started;
drmSize registerSize;
drmHandle registerHandle;
drmHandle fbHandle;
int IsAGP;
drmSize gartSize;
drmHandle agpMemHandle; /* Handle from drmAgpAlloc */
unsigned long gartOffset;
@ -196,23 +287,9 @@ typedef struct _ATIScreenInfo {
unsigned char *gartTex; /* Map */
int log2GARTTexGran;
int CCEMode; /* CCE mode that server/clients use */
int CPMode; /* CP mode that server/clients use */
int CCEFifoSize; /* Size of the CCE command FIFO */
int DMAusecTimeout; /* CCE timeout in usecs */
/* DMA 2D accleration */
drmBufPtr indirectBuffer;
int indirectStart;
/* DRI screen private data */
int fbX;
int fbY;
int backX;
int backY;
int depthX;
int depthY;
/* DRI screen private data */
int frontOffset;
int frontPitch;
int backOffset;
@ -240,13 +317,18 @@ typedef struct _ATIScreenInfo {
#define getATIScreenInfo(kd) ((ATIScreenInfo *) ((kd)->screen->driver))
#define ATIScreenInfo(kd) ATIScreenInfo *atis = getATIScreenInfo(kd)
/* ati.c */
Bool
ATIMapReg(KdCardInfo *card, ATICardInfo *atic);
void
ATIUnmapReg(KdCardInfo *card, ATICardInfo *atic);
Bool
void
R300CGWorkaround(ATIScreenInfo *atis);
/* ati_draw.c */
void
ATIDrawSetup(ScreenPtr pScreen);
Bool
@ -264,17 +346,54 @@ ATIDrawDisable(ScreenPtr pScreen);
void
ATIDrawFini(ScreenPtr pScreen);
/* ati_dri.c */
#ifdef USE_DRI
Bool
ATIDRIScreenInit(ScreenPtr pScreen);
void
ATIDRICloseScreen(ScreenPtr pScreen);
void
ATIDRIDMAStart(ScreenPtr pScreen);
void
ATIDRIDMAStop(ScreenPtr pScreen);
void
ATIDRIDispatchIndirect(ATIScreenInfo *atis, Bool discard);
drmBufPtr
ATIDRIGetBuffer(ATIScreenInfo *atis);
#endif /* USE_DRI */
/* ati_cursor.c */
Bool
ATICursorInit(ScreenPtr pScreen);
void
ATICursorEnable(ScreenPtr pScreen);
void
ATICursorDisable(ScreenPtr pScreen);
void
ATICursorFini(ScreenPtr pScreen);
void
ATIRecolorCursor(ScreenPtr pScreen, int ndef, xColorItem *pdef);
int
ATILog2(int val);
/* ati_video.c */
Bool
ATIInitVideo(ScreenPtr pScreen);
void
ATIFiniVideo(ScreenPtr pScreen);
extern KdCardFuncs ATIFuncs;
#endif /* _ATI_H_ */

392
hw/kdrive/ati/ati_cursor.c Normal file
View File

@ -0,0 +1,392 @@
/*
* Copyright © 2004 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.
*/
/* $RCSId$ */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "ati.h"
#include "ati_reg.h"
#include "cursorstr.h"
#include "ati_draw.h"
static void
ATIMoveCursor(ScreenPtr pScreen, int x, int y)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
CARD16 xoff, yoff;
CARD8 *mmio = atic->reg_base;
if (!pCurPriv->has_cursor)
return;
if (!pScreenPriv->enabled)
return;
x -= pCurPriv->xhot;
xoff = 0;
if (x < 0) {
xoff = -x;
x = 0;
}
y -= pCurPriv->yhot;
yoff = 0;
if (y < 0) {
yoff = -y;
y = 0;
}
MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_OFF, ATI_CUR_LOCK |
(xoff << 16) | yoff);
MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_POSN, ATI_CUR_LOCK |
(x << 16) | y);
MMIO_OUT32(mmio, ATI_REG_CUR_OFFSET, (pCurPriv->offset + yoff * 16));
}
static void
ATIAllocCursorColors(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
CursorPtr pCursor = pCurPriv->pCursor;
KdAllocateCursorPixels(pScreen, 0, pCursor, &pCurPriv->source,
&pCurPriv->mask);
switch (pScreenPriv->screen->fb[0].bitsPerPixel) {
case 4:
pCurPriv->source |= pCurPriv->source << 4;
pCurPriv->mask |= pCurPriv->mask << 4;
/* FALLTHROUGH */
case 8:
pCurPriv->source |= pCurPriv->source << 8;
pCurPriv->mask |= pCurPriv->mask << 8;
/* FALLTHROUGH */
case 16:
pCurPriv->source |= pCurPriv->source << 16;
pCurPriv->mask |= pCurPriv->mask << 16;
}
}
static void
ATISetCursorColors(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
CARD8 *mmio = atic->reg_base;
MMIO_OUT32(mmio, ATI_REG_CUR_CLR0, pCurPriv->mask);
MMIO_OUT32(mmio, ATI_REG_CUR_CLR1, pCurPriv->source);
}
void
ATIRecolorCursor(ScreenPtr pScreen, int ndef, xColorItem *pdef)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
CursorPtr pCursor = pCurPriv->pCursor;
if (!pCurPriv->has_cursor || !pCursor)
return;
if (!pScreenPriv->enabled)
return;
if (pdef) {
while (ndef != 0) {
if (pdef->pixel == pCurPriv->source ||
pdef->pixel == pCurPriv->mask)
break;
ndef--;
}
if (ndef == 0)
return;
}
ATIAllocCursorColors(pScreen);
ATISetCursorColors(pScreen);
}
#define InvertBits32(v) do { \
v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); \
v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); \
v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); \
} while (0)
static void
ATILoadCursor(ScreenPtr pScreen, int x, int y)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
CursorPtr pCursor = pCurPriv->pCursor;
CursorBitsPtr bits = pCursor->bits;
int h;
CARD32 *ram, *msk, *mskLine, *src, *srcLine;
int i;
int lwsrc;
CARD32 tmp;
CARD8 *mmio = atic->reg_base;
ATIAllocCursorColors(pScreen);
pCurPriv->pCursor = pCursor;
pCurPriv->xhot = pCursor->bits->xhot;
pCurPriv->yhot = pCursor->bits->yhot;
/* Stick new image into cursor memory */
ram = (CARD32 *)(pScreenPriv->screen->memory_base +
pCurPriv->offset);
mskLine = (CARD32 *)bits->mask;
srcLine = (CARD32 *)bits->source;
h = bits->height;
if (h > ATI_CURSOR_HEIGHT)
h = ATI_CURSOR_HEIGHT;
lwsrc = BitmapBytePad(bits->width) / 4; /* words per line */
tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL);
MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp & ~ATI_CRTC_CUR_EN);
for (i = 0; i < ATI_CURSOR_HEIGHT; i++) {
CARD32 m1, m2, s1, s2;
msk = mskLine;
src = srcLine;
mskLine += lwsrc;
srcLine += lwsrc;
if (i < h && 0 < lwsrc) {
m1 = ~*msk++;
s1 = *src++;
InvertBits32(m1);
InvertBits32(s1);
} else {
m1 = 0xffffffff;
s1 = 0x0;
}
if (i < h && 1 < lwsrc) {
m2 = ~*msk++;
s2 = *src++;
InvertBits32(m2);
InvertBits32(s2);
} else {
m2 = 0xffffffff;
s2 = 0x0;
}
*ram++ = m1;
*ram++ = m2;
*ram++ = s1;
*ram++ = s2;
}
/* Not sure why this is necessary, but it prevents some cursor
* corruption. Not even all of it.
*/
for (i = 0; i < ATI_CURSOR_HEIGHT; i++) {
*ram++ = 0xffffffff;
*ram++ = 0xffffffff;
*ram++ = 0x0;
*ram++ = 0x0;
}
/* Enable the cursor */
tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL);
MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp | ATI_CRTC_CUR_EN);
/* Set new color */
ATISetCursorColors(pScreen);
/* Move to new position */
ATIMoveCursor(pScreen, x, y);
}
static void
ATIUnloadCursor(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
CARD8 *mmio = atic->reg_base;
CARD32 tmp;
tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL) & ~ATI_CRTC_CUR_EN;
MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp);
}
static Bool
ATIRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
if (!pScreenPriv->enabled)
return TRUE;
/* miRecolorCursor does this */
if (pCursor && pCurPriv->pCursor == pCursor)
{
int x, y;
miPointerPosition(&x, &y);
ATILoadCursor(pScreen, x, y);
}
return TRUE;
}
static Bool
ATIUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor)
{
return TRUE;
}
static void
ATISetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
pCurPriv->pCursor = pCursor;
if (!pScreenPriv->enabled)
return;
if (pCursor)
ATILoadCursor(pScreen, x, y);
else
ATIUnloadCursor(pScreen);
}
miPointerSpriteFuncRec ATIPointerSpriteFuncs = {
ATIRealizeCursor,
ATIUnrealizeCursor,
ATISetCursor,
ATIMoveCursor,
};
static void
ATIQueryBestSize(int class, unsigned short *pwidth, unsigned short *pheight,
ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
switch (class)
{
case CursorShape:
if (*pwidth > pCurPriv->width)
*pwidth = pCurPriv->width;
if (*pheight > pCurPriv->height)
*pheight = pCurPriv->height;
if (*pwidth > pScreen->width)
*pwidth = pScreen->width;
if (*pheight > pScreen->height)
*pheight = pScreen->height;
break;
default:
fbQueryBestSize(class, pwidth, pheight, pScreen);
break;
}
}
void
ATICursorEnable(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
if (!pCurPriv->has_cursor)
return;
if (pCurPriv->pCursor) {
int x, y;
miPointerPosition(&x, &y);
ATILoadCursor(pScreen, x, y);
}
else
ATIUnloadCursor(pScreen);
}
void
ATICursorDisable(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
if (!pScreenPriv->enabled || !pCurPriv->has_cursor)
return;
if (pCurPriv->pCursor)
ATIUnloadCursor(pScreen);
}
Bool
ATICursorInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
pCurPriv->has_cursor = FALSE;
if (pCurPriv->offset == 0)
return FALSE;
if (atic->reg_base == NULL)
return FALSE;
pCurPriv->width = ATI_CURSOR_WIDTH;
pCurPriv->height= ATI_CURSOR_HEIGHT;
pScreen->QueryBestSize = ATIQueryBestSize;
miPointerInitialize(pScreen, &ATIPointerSpriteFuncs,
&kdPointerScreenFuncs, FALSE);
pCurPriv->has_cursor = TRUE;
pCurPriv->pCursor = NULL;
return TRUE;
}
void
ATICursorFini(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICursor *pCurPriv = &atis->cursor;
pCurPriv->has_cursor = FALSE;
pCurPriv->pCursor = NULL;
}

992
hw/kdrive/ati/ati_dma.c Normal file
View File

@ -0,0 +1,992 @@
/*
* Copyright © 2004 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.
*/
/* $Header$ */
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_draw.h"
#ifdef USE_DRI
#include "radeon_common.h"
#include "r128_common.h"
#include "ati_sarea.h"
#endif /* USE_DRI */
#include "agp.h"
#define DEBUG_FIFO 0
extern CARD32 r128_cce_microcode[];
extern CARD32 radeon_cp_microcode[][2];
extern CARD32 r200_cp_microcode[][2];
#if DEBUG_FIFO
static void
ATIDebugFifo(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
if (atic->is_radeon) {
ErrorF("RADEON_REG_CP_CSQ_CNTL: 0x%08x\n",
MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL));
ErrorF("RADEON_REG_CP_CSQ_STAT: 0x%08x\n",
MMIO_IN32(mmio, RADEON_REG_CP_CSQ_STAT));
ErrorF("RADEON_REG_RBBM_STATUS: 0x%08x\n",
MMIO_IN32(mmio, RADEON_REG_RBBM_STATUS));
ErrorF("RADEON_REG_RB2D_DSTCACHE_CTLSTAT: 0x%08x\n",
MMIO_IN32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT));
} else {
ErrorF("R128_REG_PM4_BUFFER_CNTL: 0x%08x\n",
MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL));
ErrorF("R128_REG_PM4_STAT: 0x%08x\n",
MMIO_IN32(mmio, R128_REG_PM4_STAT));
ErrorF("R128_REG_GUI_STAT: 0x%08x\n",
MMIO_IN32(mmio, R128_REG_GUI_STAT));
ErrorF("R128_REG_PC_NGUI_CTLSTAT: 0x%08x\n",
MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT));
}
}
#endif
static void
ATIUploadMicrocode(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
int i;
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_ADDR, 0);
if (atic->is_radeon && atic->is_r200) {
for (i = 0; i < 256; i++) {
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
r200_cp_microcode[i][1]);
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
r200_cp_microcode[i][0]);
}
} else if (atic->is_radeon && atic->is_r100) {
for (i = 0; i < 256; i++) {
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
radeon_cp_microcode[i][1]);
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
radeon_cp_microcode[i][0]);
}
} else {
for (i = 0; i < 256; i++) {
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAH,
r128_cce_microcode[i * 2]);
MMIO_OUT32(mmio, ATI_REG_MICROCODE_RAM_DATAL,
r128_cce_microcode[i * 2 + 1]);
}
}
}
/* Required when reading from video memory after acceleration to make sure all
* data has been flushed to video memory from the pixel cache.
*/
static void
ATIFlushPixelCache(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
int tries;
CARD32 temp;
if (atic->is_radeon) {
temp = MMIO_IN32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT);
temp |= RADEON_RB2D_DC_FLUSH_ALL;
MMIO_OUT32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT, temp);
for (tries = 1000000; tries != 0; tries--) {
if ((MMIO_IN32(mmio, RADEON_REG_RB2D_DSTCACHE_CTLSTAT) &
RADEON_RB2D_DC_BUSY) == 0)
break;
}
} else {
temp = MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT);
temp |= R128_PC_FLUSH_ALL;
MMIO_OUT32(mmio, R128_REG_PC_NGUI_CTLSTAT, temp);
for (tries = 1000000; tries != 0; tries--) {
if ((MMIO_IN32(mmio, R128_REG_PC_NGUI_CTLSTAT) &
R128_PC_BUSY) != R128_PC_BUSY)
break;
}
}
if (tries == 0)
ErrorF("Timeout flushing pixel cache.\n");
}
static void
ATIEngineReset(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
CARD32 clockcntlindex, mclkcntl;
#if DEBUG_FIFO
ErrorF("Engine Reset!\n");
ATIDebugFifo(atis);
#endif
ATIFlushPixelCache(atis);
clockcntlindex = MMIO_IN32(mmio, ATI_REG_CLOCK_CNTL_INDEX);
if (atic->is_r300)
R300CGWorkaround(atis);
if (atic->is_radeon) {
CARD32 host_path_cntl;
mclkcntl = INPLL(mmio, RADEON_REG_MCLK_CNTL);
OUTPLL(mmio, RADEON_REG_MCLK_CNTL, mclkcntl |
RADEON_FORCEON_MCLKA |
RADEON_FORCEON_MCLKB |
RADEON_FORCEON_YCLKA |
RADEON_FORCEON_YCLKB |
RADEON_FORCEON_MC |
RADEON_FORCEON_AIC);
host_path_cntl = MMIO_IN32(mmio, RADEON_REG_HOST_PATH_CNTL);
if (atic->is_r300) {
MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET,
RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_E2);
} else {
MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET,
RADEON_SOFT_RESET_CP |
RADEON_SOFT_RESET_HI |
RADEON_SOFT_RESET_SE |
RADEON_SOFT_RESET_RE |
RADEON_SOFT_RESET_PP |
RADEON_SOFT_RESET_E2 |
RADEON_SOFT_RESET_RB);
}
MMIO_IN32(mmio, RADEON_REG_RBBM_SOFT_RESET);
MMIO_OUT32(mmio, RADEON_REG_RBBM_SOFT_RESET, 0);
MMIO_OUT32(mmio, RADEON_REG_HOST_PATH_CNTL, host_path_cntl |
RADEON_HDP_SOFT_RESET);
MMIO_IN32(mmio, RADEON_REG_HOST_PATH_CNTL);
MMIO_OUT32(mmio, RADEON_REG_HOST_PATH_CNTL, host_path_cntl);
MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, clockcntlindex);
OUTPLL(mmio, RADEON_REG_MCLK_CNTL, mclkcntl);
if (atic->is_r300)
R300CGWorkaround(atis);
} else {
CARD32 temp;
mclkcntl = INPLL(mmio, R128_REG_MCLK_CNTL);
OUTPLL(mmio, R128_REG_MCLK_CNTL,
mclkcntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
MMIO_OUT32(mmio, R128_REG_GEN_RESET_CNTL,
temp | R128_SOFT_RESET_GUI);
temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
MMIO_OUT32(mmio, R128_REG_GEN_RESET_CNTL,
temp & ~R128_SOFT_RESET_GUI);
temp = MMIO_IN32(mmio, R128_REG_GEN_RESET_CNTL);
OUTPLL(mmio, R128_REG_MCLK_CNTL, mclkcntl);
MMIO_OUT32(mmio, ATI_REG_CLOCK_CNTL_INDEX, clockcntlindex);
}
}
static void
ATIWaitAvailMMIO(ATIScreenInfo *atis, int n)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
int tries;
if (atis->mmio_avail >= n) {
atis->mmio_avail -= n;
return;
}
if (atic->is_radeon) {
for (tries = 1000000; tries != 0 && atis->mmio_avail < n; tries--)
{
atis->mmio_avail = MMIO_IN32(mmio,
RADEON_REG_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK;
}
} else {
for (tries = 1000000; tries != 0 && atis->mmio_avail < n; tries--)
{
atis->mmio_avail = MMIO_IN32(mmio, R128_REG_GUI_STAT) &
0xfff;
}
}
if (tries == 0) {
ErrorF("Timeout waiting for %d MMIO slots.\n", n);
ATIEngineReset(atis);
}
atis->mmio_avail -= n;
}
static int
ATIGetAvailPrimary(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
if (atic->is_radeon) {
int csq_stat, diff;
csq_stat = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_STAT);
diff = ((csq_stat & RADEON_CSQ_WPTR_PRIMARY_MASK) >> 8) -
(csq_stat & RADEON_CSQ_RPTR_PRIMARY_MASK);
if (diff < 0)
return -diff;
else
return atis->cce_pri_size - diff;
} else {
return MMIO_IN32(mmio, R128_REG_PM4_STAT) &
R128_PM4_FIFOCNT_MASK;
}
}
static void
ATIWaitAvailPrimary(ATIScreenInfo *atis, int n)
{
int tries;
if (atis->cce_pri_avail >= n) {
atis->cce_pri_avail -= n;
return;
}
for (tries = 1000000; tries != 0 && atis->cce_pri_avail < n; tries--)
{
atis->cce_pri_avail = ATIGetAvailPrimary(atis);
if (atis->cce_pri_avail >= n)
break;
}
if (tries == 0) {
ErrorF("Timeout waiting for %d CCE slots (%d avail).\n", n,
atis->cce_pri_avail);
ATIEngineReset(atis);
}
atis->cce_pri_avail -= n;
}
void
ATIWaitIdle(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
int tries;
char *mmio = atic->reg_base;
RING_LOCALS;
if (atis->indirectBuffer != NULL)
ATIFlushIndirect(atis, 0);
#ifdef USE_DRI
if (atis->using_dri) {
int ret;
int cmd = (atic->is_radeon ? DRM_RADEON_CP_IDLE :
DRM_R128_CCE_IDLE);
do {
ret = drmCommandNone(atic->drmFd, cmd);
} while (ret == -EBUSY);
if (ret != 0)
ErrorF("Failed to idle DMA, returned %d\n", ret);
return;
}
#endif
if (atic->is_radeon && (atis->using_pseudo || atis->using_dma)) {
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB2D_DSTCACHE_CTLSTAT,
RADEON_RB2D_DC_FLUSH_ALL);
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_3D_IDLECLEAN);
END_DMA();
}
if (!atic->is_radeon && (atis->using_pseudo || atis->using_dma)) {
ATIWaitAvailPrimary(atis, atis->cce_pri_size);
for (tries = 1000000; tries != 0; tries--) {
if ((MMIO_IN32(mmio, R128_REG_PM4_STAT) &
(R128_PM4_BUSY | R128_PM4_GUI_ACTIVE)) == 0)
break;
}
if (tries == 0) {
ErrorF("Timeout idling CCE, resetting...\n");
ATIEngineReset(atis);
}
}
/* Radeon CP idle is the same as MMIO idle. */
if (atis->using_pio || atic->is_radeon) {
/* Empty the fifo */
ATIWaitAvailMMIO(atis, 64);
if (atic->is_radeon) {
for (tries = 1000000; tries != 0; tries--) {
if ((MMIO_IN32(mmio, RADEON_REG_RBBM_STATUS) &
RADEON_RBBM_ACTIVE) == 0)
break;
}
} else {
for (tries = 1000000; tries != 0; tries--) {
if ((MMIO_IN32(mmio, R128_REG_GUI_STAT) &
R128_GUI_ACTIVE) == 0)
break;
}
}
if (tries == 0) {
ErrorF("Timeout idling accelerator, resetting...\n");
ATIEngineReset(atis);
}
}
ATIFlushPixelCache(atis);
#if DEBUG_FIFO
ErrorF("Idle?\n");
ATIDebugFifo(atis);
#endif
}
dmaBuf *
ATIGetDMABuffer(ATIScreenInfo *atis)
{
dmaBuf *buf;
buf = (dmaBuf *)xalloc(sizeof(dmaBuf));
if (buf == NULL)
return NULL;
#ifdef USE_DRI
if (atis->using_dri) {
buf->drmBuf = ATIDRIGetBuffer(atis);
if (buf->drmBuf == NULL) {
xfree(buf);
return NULL;
}
buf->size = buf->drmBuf->total;
buf->used = buf->drmBuf->used;
buf->address = buf->drmBuf->address;
return buf;
}
#endif /* USE_DRI */
if (atis->using_dma)
buf->size = atis->ring_len / 2;
else
buf->size = 512 * 1024;
buf->address = xalloc(buf->size);
if (buf->address == NULL) {
xfree(buf);
return NULL;
}
buf->used = 0;
return buf;
}
/* Decode a type-3 packet into MMIO register writes. Only some type-3 packets
* supported, and only partially.
*/
static void
ATIDispatchPacket3MMIO(ATIScreenInfo *atis, CARD32 header, CARD32 *addr,
int count)
{
ATICardInfo *atic = atis->atic;
char *mmio = atic->reg_base;
CARD32 settings;
int i = 0;
settings = addr[i++];
if ((settings & ATI_GMC_SRC_PITCH_OFFSET_CNTL) != 0)
MMIO_OUT32(mmio, ATI_REG_SRC_PITCH_OFFSET, addr[i++]);
if ((settings & ATI_GMC_DST_PITCH_OFFSET_CNTL) != 0)
MMIO_OUT32(mmio, ATI_REG_DST_PITCH_OFFSET, addr[i++]);
if ((settings & ATI_GMC_BRUSH_MASK) == ATI_GMC_BRUSH_SOLID_COLOR)
MMIO_OUT32(mmio, ATI_REG_DP_BRUSH_FRGD_CLR, addr[i++]);
switch (header & (ATI_CCE_PACKETTYPE_MASK |
ATI_CCE_PACKET3_IT_OPCODE_MASK))
{
case ATI_CCE_PACKET3_PAINT_MULTI:
while (i < count) {
MMIO_OUT32(mmio, ATI_REG_DST_Y_X,
(addr[i] >> 16) | (addr[i] << 16));
i++;
MMIO_OUT32(mmio, ATI_REG_DST_HEIGHT_WIDTH,
(addr[i] >> 16) | (addr[i] << 16));
i++;
}
break;
case ATI_CCE_PACKET3_BITBLT_MULTI:
while (i < count) {
MMIO_OUT32(mmio, ATI_REG_SRC_Y_X,
(addr[i] >> 16) | (addr[i] << 16));
i++;
MMIO_OUT32(mmio, ATI_REG_DST_Y_X,
(addr[i] >> 16) | (addr[i] << 16));
i++;
MMIO_OUT32(mmio, ATI_REG_DST_HEIGHT_WIDTH,
(addr[i] >> 16) | (addr[i] << 16));
i++;
}
break;
default:
ErrorF("Unsupported packet: 0x%x\n", header);
}
}
/* Dispatch packets by decoding them and writing to registers. Doesn't support
* the type 3 packets.
*/
static void
ATIDispatchIndirectMMIO(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
dmaBuf *buf = atis->indirectBuffer;
char *mmio = atic->reg_base;
CARD32 *addr;
CARD32 reg;
int i, n, count;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
for (i = 0; i < count; i++) {
CARD32 header = addr[i];
switch (header & ATI_CCE_PACKETTYPE_MASK)
{
case ATI_CCE_PACKET0:
n = ((header & ATI_CCE_PACKET0_COUNT_MASK) >> 16) + 1;
reg = (header & ATI_CCE_PACKET0_REG_MASK) << 2;
ATIWaitAvailMMIO(atis, n);
while (n > 0) {
i++;
MMIO_OUT32(mmio, reg, addr[i]);
if ((header & ATI_CCE_PACKET0_ONE_REG_WR) == 0)
reg += 4;
n--;
}
break;
case ATI_CCE_PACKET1:
reg = (header & ATI_CCE_PACKET1_REG_1) << 2;
MMIO_OUT32(mmio, reg, addr[++i]);
reg = ((header & ATI_CCE_PACKET1_REG_2) >>
ATI_CCE_PACKET1_REG_2_SHIFT) << 2;
MMIO_OUT32(mmio, reg, addr[++i]);
break;
case ATI_CCE_PACKET2:
/* PACKET2 is a no-op packet. */
break;
case ATI_CCE_PACKET3:
n = ((header & ATI_CCE_PACKET3_COUNT_MASK) >> 16) + 1;
ATIDispatchPacket3MMIO(atis, header, &addr[i], n);
i += n;
break;
default:
ErrorF("Unsupported packet: 0x%x\n", addr[i]);
}
}
}
/* Dispatch packets by sending them through the MMIO aperture. */
static void
R128DispatchIndirectPDMA(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
dmaBuf *buf = atis->indirectBuffer;
char *mmio = atic->reg_base;
CARD32 *addr;
int count;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
while (count > 1) {
ATIWaitAvailPrimary(atis, 2);
MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_EVEN, *addr++);
MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_ODD, *addr++);
count -= 2;
}
/* Submit last DWORD if necessary. */
if (count != 0) {
ATIWaitAvailPrimary(atis, 2);
MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_EVEN, *addr++);
MMIO_OUT32(mmio, R128_REG_PM4_FIFO_DATA_ODD, ATI_CCE_PACKET2);
}
}
/* Dispatch packets by sending them through the MMIO aperture, using the
* primary CCE ring. */
static void
RadeonDispatchIndirectPDMA(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
dmaBuf *buf = atis->indirectBuffer;
char *mmio = atic->reg_base;
CARD32 *addr;
int count, avail, reg, i;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
reg = RADEON_REG_CSQ_APER_PRIMARY;
while (count > 0) {
avail = ATIGetAvailPrimary(atis);
for (i = 0; i < min(count, avail); i++) {
MMIO_OUT32(mmio, reg, *addr++);
if (reg == RADEON_REG_CSQ_APER_PRIMARY_END)
reg = RADEON_REG_CSQ_APER_PRIMARY;
else
reg += 4;
}
count -= i;
}
}
/* Dispatch packets by writing them to the (primary) ring buffer, which happens
* to be in framebuffer memory.
*/
static void
R128DispatchIndirectDMA(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
dmaBuf *buf = atis->indirectBuffer;
char *mmio = atic->reg_base;
CARD32 *addr;
int count, ring_count;
addr = (CARD32 *)((char *)buf->address + atis->indirectStart);
count = (buf->used - atis->indirectStart) / 4;
ring_count = atis->ring_len / 4;
while (count > 0) {
int tries = 0;
atis->ring_addr[atis->ring_write++] = *addr++;
if (atis->ring_write >= ring_count)
atis->ring_write = 0;
while (atis->ring_write == atis->ring_read) {
atis->ring_read = MMIO_IN32(mmio, ATI_REG_CCE_RPTR);
if (tries++ == 1000000) {
ErrorF("Timeout submitting packets, resetting...\n");
ATIEngineReset(atis);
}
}
count--;
}
/* Workaround for some early Rage 128 ASIC spins where the CCE parser
* may read up to 32 DWORDS beyond the end of the ring buffer memory
* before wrapping around, if the ring buffer was empty and a <32 DWORD
* packet that wraps around the end of the ring buffer is submitted.
* To work around that, copy the beginning of the ring buffer past the
* end if that may happen.
*/
if (atis->ring_write < 32)
memcpy(atis->ring_addr + ring_count, atis->ring_addr, 32 * 4);
/* Update write pointer */
MMIO_OUT32(mmio, ATI_REG_CCE_WPTR, atis->ring_write);
}
void
ATIFlushIndirect(ATIScreenInfo *atis, Bool discard)
{
ATICardInfo *atic = atis->atic;
dmaBuf *buf = atis->indirectBuffer;
if ((atis->indirectStart == buf->used) && !discard)
return;
#if DEBUG_FIFO
ErrorF("Dispatching %d DWORDS\n", (buf->used - atis->indirectStart) /
4);
#endif
#ifdef USE_DRI
if (atis->using_dri) {
buf->drmBuf->used = buf->used;
ATIDRIDispatchIndirect(atis, discard);
if (discard) {
buf->drmBuf = ATIDRIGetBuffer(atis);
buf->size = buf->drmBuf->total;
buf->used = buf->drmBuf->used;
buf->address = buf->drmBuf->address;
atis->indirectStart = 0;
} else {
/* Start on a double word boundary */
atis->indirectStart = buf->used = (buf->used + 7) & ~7;
}
return;
}
#endif /* USE_DRI */
if (atis->using_dma && !atic->is_radeon)
R128DispatchIndirectDMA(atis);
else if (atis->using_pseudo) {
if (atic->is_radeon)
RadeonDispatchIndirectPDMA(atis);
else
R128DispatchIndirectPDMA(atis);
} else
ATIDispatchIndirectMMIO(atis);
buf->used = 0;
atis->indirectStart = 0;
}
static Bool
ATIInitAGP(ScreenPtr pScreen, int size)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
AgpInfoPtr agp_info;
int screennum = atis->screen->mynum;
if (atic->is_radeon)
return FALSE;
if (!KdAgpGARTSupported())
return FALSE;
if (!KdAcquireGART(screennum))
return FALSE;
atis->agp_key = KdAllocateGARTMemory(screennum, size, 0, NULL);
if (atis->agp_key == -1) {
ErrorF("Failed to allocate %dKB GART memory\n", size/1024);
KdReleaseGART(screennum);
return FALSE;
}
if (!KdBindGARTMemory(screennum, atis->agp_key, 0)) {
ErrorF("Failed to bind GART memory\n");
KdReleaseGART(screennum);
return FALSE;
}
agp_info = KdGetAGPInfo(screennum);
if (agp_info == NULL) {
KdUnbindGARTMemory(screennum, atis->agp_key);
KdReleaseGART(screennum);
return FALSE;
}
atis->agp_addr = KdMapDevice(agp_info->base, agp_info->size);
if (atis->agp_addr == NULL) {
ErrorF("Failed to map GART memory\n");
KdUnbindGARTMemory(screennum, atis->agp_key);
KdReleaseGART(screennum);
free(agp_info);
return FALSE;
}
KdSetMappedMode(agp_info->base, agp_info->size,
KD_MAPPED_MODE_FRAMEBUFFER);
atis->agp_size = size;
free(agp_info);
return TRUE;
}
static void
ATIFiniAGP(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
int screennum = atis->screen->mynum;
KdUnbindGARTMemory(screennum, atis->agp_key);
KdReleaseGART(screennum);
atis->agp_addr = NULL;
atis->agp_size = 0;
}
static Bool
ATIPseudoDMAInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
char *mmio = atic->reg_base;
/* XXX: The Radeon pseudo-dma code is untested. */
if (0 && atic->is_radeon)
return FALSE;
ATIUploadMicrocode(atis);
ATIEngineReset(atis);
if (atic->is_radeon) {
MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
RADEON_CSQ_PRIPIO_INDDIS);
atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
RADEON_CSQ_CNT_PRIMARY_MASK;
MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
} else {
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL, R128_PM4_192PIO |
R128_PM4_BUFFER_CNTL_NOUPDATE);
atis->cce_pri_size = 192;
MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL,
R128_PM4_MICRO_FREERUN);
}
return TRUE;
}
static Bool
ATIPseudoDMAFini(ScreenPtr pScreen)
{ KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
char *mmio = atic->reg_base;
if (atic->is_radeon) {
MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, 0);
MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
RADEON_CSQ_PRIDIS_INDDIS);
} else {
MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL, 0);
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
}
atis->cce_pri_size = 0;
ATIEngineReset(atis);
return TRUE;
}
static Bool
ATIDMAInit(ScreenPtr pScreen, Bool use_agp)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
char *mmio = atic->reg_base;
int dma_offset;
CARD32 tmp;
/* XXX: Not for radeons. Yet? */
if (atic->is_radeon)
return FALSE;
if (use_agp) {
if (1)
return FALSE; /* XXX */
/* Allocate a 1MB AGP space, but only use 128k + 128 for DMA.
* XXX: Should use the rest for things like scratch space.
*/
if (!ATIInitAGP(pScreen, 1024 * 1024))
return FALSE;
atis->ring_addr = atis->agp_addr;
atis->ring_len = 128 * 1024;
dma_offset = R128_AGP_OFFSET;
} else {
if (1)
return FALSE; /* XXX */
/* Allocate a 128K buffer, plus 32 DWORDS to give space for the
* R128 ASIC bug workaround.
*/
atis->dma_space = KdOffscreenAlloc(pScreen, 128 * 1024 + 128,
128, TRUE, NULL, NULL);
if (atis->dma_space == NULL)
return FALSE;
atis->ring_addr = (CARD32 *)(atis->dma_space->offset +
pScreenPriv->screen->memory_base);
atis->ring_len = 128 * 1024;
dma_offset = atis->dma_space->offset;
}
ATIUploadMicrocode(atis);
ATIEngineReset(atis);
atis->ring_read = 0;
atis->ring_write = 0;
tmp = MMIO_IN32(mmio, ATI_REG_BUS_CNTL);
MMIO_OUT32(mmio, ATI_REG_BUS_CNTL, tmp & ~ATI_BUS_MASTER_DIS);
MMIO_OUT32(mmio, ATI_REG_CCE_RB_BASE, dma_offset);
MMIO_OUT32(mmio, ATI_REG_CCE_WPTR, atis->ring_write);
MMIO_OUT32(mmio, ATI_REG_CCE_RPTR, atis->ring_read);
MMIO_OUT32(mmio, ATI_REG_CCE_RPTR_ADDR, 0 /* XXX? */);
if (atic->is_radeon) {
MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
RADEON_CSQ_PRIBM_INDBM);
atis->cce_pri_size = MMIO_IN32(mmio, RADEON_REG_CP_CSQ_CNTL) &
RADEON_CSQ_CNT_PRIMARY_MASK;
MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, RADEON_ME_MODE_FREE_RUN);
} else {
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_WM_CNTL,
((R128_WATERMARK_L/4) << R128_WMA_SHIFT) |
((R128_WATERMARK_M/4) << R128_WMB_SHIFT) |
((R128_WATERMARK_N/4) << R128_WMC_SHIFT) |
((R128_WATERMARK_K/64) << R128_WB_WM_SHIFT));
/* The sample code reads from an undocumneted register
* (PM4_BUFFER_ADDR). Perhaps it's a write posting thing? Do
* a read in case that's it.
*/
MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL);
if (use_agp) {
/* XXX Magic num */
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 1);
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
ATILog2(atis->ring_len) |
R128_PM4_192BM |
R128_PM4_BUFFER_CNTL_NOUPDATE);
} else {
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
ATILog2(atis->ring_len) |
R128_PM4_192BM |
R128_PM4_BUFFER_CNTL_NOUPDATE |
R128_PM4_IN_FRAME_BUFFER);
}
atis->cce_pri_size = 192;
MMIO_IN32(mmio, R128_REG_PM4_BUFFER_CNTL);
MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL,
R128_PM4_MICRO_FREERUN);
}
return TRUE;
}
static Bool
ATIDMAFini(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
char *mmio = atic->reg_base;
if (atic->is_radeon) {
MMIO_OUT32(mmio, RADEON_REG_ME_CNTL, 0);
MMIO_OUT32(mmio, RADEON_REG_CP_CSQ_CNTL,
RADEON_CSQ_PRIDIS_INDDIS);
} else {
MMIO_OUT32(mmio, ATI_REG_CCE_WPTR,
atis->ring_write | R128_PM4_BUFFER_DL_DONE);
MMIO_OUT32(mmio, R128_REG_PM4_MICRO_CNTL, 0);
MMIO_OUT32(mmio, R128_REG_PM4_BUFFER_CNTL,
R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
}
atis->cce_pri_size = 0;
ATIEngineReset(atis);
if (atis->using_agp)
ATIFiniAGP(pScreen);
else
KdOffscreenFree(pScreen, atis->dma_space);
return TRUE;
}
void
ATIDMASetup(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
#ifdef USE_DRI
if (atis->using_dri)
ATIDRIDMAStart(pScreen);
#endif /* USE_DRI */
if (!atis->using_dri) {
atis->using_agp = FALSE;
if (atic->is_agp && ATIDMAInit(pScreen, TRUE)) {
atis->using_agp = TRUE;
atis->using_dma = TRUE;
} else if (ATIDMAInit(pScreen, FALSE)) {
atis->using_agp = FALSE;
atis->using_dma = TRUE;
} else if (ATIPseudoDMAInit(pScreen))
atis->using_pseudo = TRUE;
else
atis->using_pio = TRUE;
}
atis->indirectBuffer = ATIGetDMABuffer(atis);
if (atis->indirectBuffer == FALSE)
FatalError("Failed to allocate DMA buffer.\n");
if (atis->using_dri)
ErrorF("Initialized %s DRI DMA\n",
atis->using_agp ? "AGP" : "PCI");
else if (atis->using_dma && atis->using_agp)
ErrorF("Initialized AGP DMA\n");
else if (atis->using_dma)
ErrorF("Initialized framebuffer pseudo-DMA\n");
else if (atis->using_pseudo)
ErrorF("Initialized pseudo-DMA\n");
else if (atis->using_pio)
ErrorF("Initialized PIO\n");
}
void
ATIDMATeardown(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATIWaitIdle(atis);
#ifdef USE_DRI
if (atis->using_dri)
ATIDRIDMAStop(pScreen);
#endif /* USE_DRI */
if (atis->using_dma)
ATIDMAFini(pScreen);
if (atis->using_pseudo)
ATIPseudoDMAFini(pScreen);
if (atis->using_pio || atis->using_pseudo || atis->using_dma) {
xfree(atis->indirectBuffer->address);
xfree(atis->indirectBuffer);
}
atis->indirectBuffer = NULL;
atis->using_pio = FALSE;
atis->using_pseudo = FALSE;
atis->using_dma = FALSE;
atis->using_agp = FALSE;
}

97
hw/kdrive/ati/ati_dma.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright © 2004 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.
*/
/* $Header$ */
#ifndef _ATI_DMA_H_
#define _ATI_DMA_H_
#define DMA_PACKET0(reg, count) \
(ATI_CCE_PACKET0 | (((count) - 1) << 16) | ((reg) >> 2))
#define DMA_PACKET1(reg1, reg2) \
(ATI_CCE_PACKET1 | \
(((reg2) >> 2) << ATI_CCE_PACKET1_REG_2_SHIFT) | ((reg1) >> 2))
#define DMA_PACKET3(type, count) \
((type) | (((count) - 1) << 16))
#if 0 /* CCE non-debug */
#define RING_LOCALS CARD32 *__head; int __count
#define BEGIN_DMA(n) \
do { \
if ((atis->indirectBuffer->used + 4*(n)) > \
atis->indirectBuffer->size) { \
ATIFlushIndirect(atis, 1); \
} \
__head = (CARD32 *)((char *)atis->indirectBuffer->address + \
atis->indirectBuffer->used); \
__count = 0; \
} while (0)
#define END_DMA() do { \
atis->indirectBuffer->used += __count * 4; \
} while (0)
#else
#define RING_LOCALS CARD32 *__head; int __count; int __total
#define BEGIN_DMA(n) \
do { \
if ((atis->indirectBuffer->used + 4*(n)) > \
atis->indirectBuffer->size) { \
ATIFlushIndirect(atis, 1); \
} \
__head = (CARD32 *)((char *)atis->indirectBuffer->address + \
atis->indirectBuffer->used); \
__count = 0; \
__total = n; \
} while (0)
#define END_DMA() do { \
if (__count != __total) \
ErrorF("count != total (%d vs %d) at %s:%d\n", __count, \
__total, __FILE__, __LINE__); \
atis->indirectBuffer->used += __count * 4; \
} while (0)
#endif
#define OUT_RING(x) do { \
__head[__count++] = (x); \
} while (0)
#define OUT_REG(reg, val) \
do { \
OUT_RING(DMA_PACKET0(reg, 1)); \
OUT_RING(val); \
} while (0)
dmaBuf *
ATIGetDMABuffer(ATIScreenInfo *atis);
void
ATIFlushIndirect(ATIScreenInfo *atis, Bool discard);
void
ATIDMASetup(ScreenPtr pScreen);
void
ATIDMATeardown(ScreenPtr pScreen);
#endif /* _ATI_DMA_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
/*
* $Id$
*
* Copyright © 2003 Eric Anholt
* Copyright © 2004 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
@ -26,63 +24,69 @@
#ifndef _ATI_DRAW_H_
#define _ATI_DRAW_H_
#ifdef USE_DRI
Bool
ATIGetOffsetPitch(ATIScreenInfo *atis, int bpp, CARD32 *pitch_offset,
int offset, int pitch);
#define DMA_PACKET0( reg, n ) \
(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
Bool
ATIGetPixmapOffsetPitch(PixmapPtr pPix, CARD32 *pitch_offset);
#define RING_LOCALS CARD32 *__head; int __count;
#define BEGIN_RING( n ) \
do { \
if (atis->indirectBuffer == NULL) { \
atis->indirectBuffer = ATIDMAGetBuffer(); \
atis->indirectStart = 0; \
} else if ((atis->indirectBuffer->used + 4*(n)) > \
atis->indirectBuffer->total) { \
ATIDMAFlushIndirect(1); \
} \
__head = (pointer)((char *)atis->indirectBuffer->address + \
atis->indirectBuffer->used); \
__count = 0; \
} while (0)
#define ADVANCE_RING() do { \
atis->indirectBuffer->used += __count * (int)sizeof(CARD32); \
} while (0)
#define OUT_RING(x) do { \
MMIO_OUT32(&__head[__count++], 0, (x)); \
} while (0)
#define OUT_RING_REG(reg, val) \
do { \
OUT_RING(DMA_PACKET0(reg, 0)); \
OUT_RING(val); \
} while (0)
drmBufPtr ATIDMAGetBuffer(void);
void ATIDMAFlushIndirect(Bool discard);
void ATIDMADispatchIndirect(Bool discard);
void ATIDMAStart(ScreenPtr pScreen);
void ATIDMAStop(ScreenPtr pScreen);
Bool RadeonPrepareBlend(int op, PicturePtr pSrcPicture, PicturePtr pDstPicture,
Bool
R128PrepareBlend(int op, PicturePtr pSrcPicture, PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pDst);
void RadeonBlend(int srcX, int srcY, int dstX, int dstY, int width, int height);
Bool RadeonPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
void RadeonDoneBlend(void);
void RadeonComposite(int srcX, int srcY, int maskX, int maskY, int dstX,
int dstY, int w, int h);
void RadeonDoneComposite(void);
void RadeonSwitchTo2D(void);
void RadeonSwitchTo3D(void);
#endif /* USE_DRI */
void
ATIWaitIdle(void);
R128Blend(int srcX, int srcY, int dstX, int dstY, int width, int height);
void
R128DoneBlend(void);
Bool
R128CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture);
Bool
R128PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
void
R128Composite(int srcX, int srcY, int maskX, int maskY, int dstX, int dstY,
int w, int h);
void
R128DoneComposite(void);
Bool
R100CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture);
Bool
R100PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
Bool
R200CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture);
Bool
R200PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
void
RadeonComposite(int srcX, int srcY, int maskX, int maskY, int dstX,
int dstY, int w, int h);
void
RadeonDoneComposite(void);
void
RadeonSwitchTo2D(ATIScreenInfo *atis);
void
RadeonSwitchTo3D(ATIScreenInfo *atis);
void
ATIWaitIdle(ATIScreenInfo *atis);
#if 0
#define ATI_FALLBACK(x) \

View File

@ -28,6 +28,7 @@
#endif
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_dri.h"
#include "ati_dripriv.h"
#include "sarea.h"
@ -67,8 +68,6 @@ static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
if (depth != 16 && (depth != 24 || bpp != 32))
ErrorF("DRI GLX unsupported at %d/%d depth/bpp\n", depth, bpp);
/* Same number of configs for 16 and 24bpp, so I factored this part out.
*/
if (atis->depthOffset != 0)
use_db = 1;
else
@ -89,15 +88,15 @@ static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
}
i = 0;
if (depth == 16) {
for (db = 0; db <= use_db; db++) {
for (accum = 0; accum <= 1; accum++) {
for (stencil = 0; stencil <= 1; stencil++) {
pATIConfigPtrs[i] = &pATIConfigs[i];
pConfigs[i].vid = (VisualID)(-1);
pConfigs[i].class = -1;
pConfigs[i].rgba = TRUE;
for (db = 0; db <= use_db; db++) {
for (accum = 0; accum <= 1; accum++) {
for (stencil = 0; stencil <= 1; stencil++) {
pATIConfigPtrs[i] = &pATIConfigs[i];
pConfigs[i].vid = (VisualID)(-1);
pConfigs[i].class = -1;
pConfigs[i].rgba = TRUE;
if (depth == 16) {
pConfigs[i].redSize = 5;
pConfigs[i].greenSize = 6;
pConfigs[i].blueSize = 5;
@ -106,54 +105,7 @@ static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
pConfigs[i].greenMask = 0x000007E0;
pConfigs[i].blueMask = 0x0000001F;
pConfigs[i].alphaMask = 0x00000000;
if (accum) { /* Simulated in software */
pConfigs[i].accumRedSize = 16;
pConfigs[i].accumGreenSize = 16;
pConfigs[i].accumBlueSize = 16;
pConfigs[i].accumAlphaSize = 0;
} else {
pConfigs[i].accumRedSize = 0;
pConfigs[i].accumGreenSize = 0;
pConfigs[i].accumBlueSize = 0;
pConfigs[i].accumAlphaSize = 0;
}
if (db)
pConfigs[i].doubleBuffer = TRUE;
else
pConfigs[i].doubleBuffer = FALSE;
pConfigs[i].stereo = FALSE;
pConfigs[i].bufferSize = 16;
pConfigs[i].depthSize = 16;
if (stencil)
pConfigs[i].stencilSize = 8;
else
pConfigs[i].stencilSize = 0;
pConfigs[i].auxBuffers = 0;
pConfigs[i].level = 0;
if (accum) {
pConfigs[i].visualRating = GLX_SLOW_CONFIG;
} else {
pConfigs[i].visualRating = GLX_NONE;
}
pConfigs[i].transparentPixel = GLX_NONE;
pConfigs[i].transparentRed = 0;
pConfigs[i].transparentGreen = 0;
pConfigs[i].transparentBlue = 0;
pConfigs[i].transparentAlpha = 0;
pConfigs[i].transparentIndex = 0;
i++;
}
}
}
} else {
for (db = 0; db <= use_db; db++) {
for (accum = 0; accum <= 1; accum++) {
for (stencil = 0; stencil <= 1; stencil++) {
pATIConfigPtrs[i] = &pATIConfigs[i];
pConfigs[i].vid = (VisualID)(-1);
pConfigs[i].class = -1;
pConfigs[i].rgba = TRUE;
} else {
pConfigs[i].redSize = 8;
pConfigs[i].greenSize = 8;
pConfigs[i].blueSize = 8;
@ -162,22 +114,34 @@ static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
pConfigs[i].greenMask = 0x0000FF00;
pConfigs[i].blueMask = 0x000000FF;
pConfigs[i].alphaMask = 0xFF000000;
if (accum) { /* Simulated in software */
pConfigs[i].accumRedSize = 16;
pConfigs[i].accumGreenSize = 16;
pConfigs[i].accumBlueSize = 16;
pConfigs[i].accumAlphaSize = 16;
} else {
pConfigs[i].accumRedSize = 0;
pConfigs[i].accumGreenSize = 0;
pConfigs[i].accumBlueSize = 0;
pConfigs[i].accumAlphaSize = 0;
}
if (db)
pConfigs[i].doubleBuffer = TRUE;
}
if (accum) { /* Simulated in software */
pConfigs[i].accumRedSize = 16;
pConfigs[i].accumGreenSize = 16;
pConfigs[i].accumBlueSize = 16;
if (depth == 16)
pConfigs[i].accumAlphaSize = 0;
else
pConfigs[i].doubleBuffer = FALSE;
pConfigs[i].stereo = FALSE;
pConfigs[i].accumAlphaSize = 16;
} else {
pConfigs[i].accumRedSize = 0;
pConfigs[i].accumGreenSize = 0;
pConfigs[i].accumBlueSize = 0;
pConfigs[i].accumAlphaSize = 0;
}
if (db)
pConfigs[i].doubleBuffer = TRUE;
else
pConfigs[i].doubleBuffer = FALSE;
pConfigs[i].stereo = FALSE;
if (depth == 16) {
pConfigs[i].bufferSize = 16;
pConfigs[i].depthSize = 16;
if (stencil)
pConfigs[i].stencilSize = 8;
else
pConfigs[i].stencilSize = 0;
} else {
pConfigs[i].bufferSize = 32;
if (stencil) {
pConfigs[i].depthSize = 24;
@ -186,23 +150,23 @@ static Bool ATIInitVisualConfigs(ScreenPtr pScreen)
pConfigs[i].depthSize = 24;
pConfigs[i].stencilSize = 0;
}
pConfigs[i].auxBuffers = 0;
pConfigs[i].level = 0;
if (accum) {
pConfigs[i].visualRating = GLX_SLOW_CONFIG;
} else {
pConfigs[i].visualRating = GLX_NONE;
}
pConfigs[i].transparentPixel = GLX_NONE;
pConfigs[i].transparentRed = 0;
pConfigs[i].transparentGreen = 0;
pConfigs[i].transparentBlue = 0;
pConfigs[i].transparentAlpha = 0;
pConfigs[i].transparentIndex = 0;
i++;
}
}
}
pConfigs[i].auxBuffers = 0;
pConfigs[i].level = 0;
if (accum) {
pConfigs[i].visualRating = GLX_SLOW_CONFIG;
} else {
pConfigs[i].visualRating = GLX_NONE;
}
pConfigs[i].transparentPixel = GLX_NONE;
pConfigs[i].transparentRed = 0;
pConfigs[i].transparentGreen = 0;
pConfigs[i].transparentBlue = 0;
pConfigs[i].transparentAlpha = 0;
pConfigs[i].transparentIndex = 0;
i++;
}
}
}
atis->numVisualConfigs = numConfigs;
@ -224,18 +188,18 @@ ATIDRIInitGARTValues(ScreenPtr pScreen)
/* Initialize the ring buffer data */
atis->ringStart = atis->gartOffset;
atis->ringMapSize = atis->ringSize*1024*1024 + DRM_PAGE_SIZE;
atis->ringMapSize = atis->ringSize * 1024 * 1024 + DRM_PAGE_SIZE;
atis->ringReadOffset = atis->ringStart + atis->ringMapSize;
atis->ringReadMapSize = DRM_PAGE_SIZE;
/* Reserve space for vertex/indirect buffers */
atis->bufStart = atis->ringReadOffset + atis->ringReadMapSize;
atis->bufMapSize = atis->bufSize*1024*1024;
atis->bufMapSize = atis->bufSize * 1024 * 1024;
/* Reserve the rest for GART textures */
atis->gartTexStart = atis->bufStart + atis->bufMapSize;
s = (atis->gartSize*1024*1024 - atis->gartTexStart);
s = (atis->gartSize * 1024 * 1024 - atis->gartTexStart);
l = ATILog2((s-1) / ATI_NR_TEX_REGIONS);
if (l < ATI_LOG_TEX_GRANULARITY) l = ATI_LOG_TEX_GRANULARITY;
atis->gartTexMapSize = (s >> l) << l;
@ -258,10 +222,10 @@ ATIDRIAddAndMap(int fd, drmHandle offset, drmSize size,
ErrorF("[%s] %s handle = 0x%08lx\n", name, desc, *handle);
if (drmMap(fd, *handle, size, address) < 0) {
ErrorF("[agp] Could not map %s\n", name, desc);
ErrorF("[%s] Could not map %s\n", name, desc);
return FALSE;
}
ErrorF("[%s] %s mapped at 0x%08lx\n", name, desc, address);
ErrorF("[%s] %s mapped at 0x%08lx\n", name, desc, *address);
return TRUE;
}
@ -280,6 +244,10 @@ ATIDRIAgpInit(ScreenPtr pScreen)
unsigned long agpBase;
CARD32 cntl, chunk;
/* AGP DRI seems broken on my R128, not sure why. */
if (!atic->is_radeon)
return FALSE;
if (drmAgpAcquire(atic->drmFd) < 0) {
ErrorF("[agp] AGP not available\n");
return FALSE;
@ -306,20 +274,20 @@ ATIDRIAgpInit(ScreenPtr pScreen)
}
/* Workaround for some hardware bugs */
/* XXX: Magic numbers */
if (!atic->is_r200) {
cntl = MMIO_IN32(mmio, RADEON_REG_AGP_CNTL) | 0x000e0000;
MMIO_OUT32(mmio, RADEON_REG_AGP_CNTL, cntl);
if (atic->is_r100) {
cntl = MMIO_IN32(mmio, ATI_REG_AGP_CNTL);
MMIO_OUT32(mmio, ATI_REG_AGP_CNTL, cntl |
RADEON_PENDING_SLOTS_VAL | RADEON_PENDING_SLOTS_SEL);
}
if ((ret = drmAgpAlloc(atic->drmFd, atis->gartSize*1024*1024, 0, NULL,
&atis->agpMemHandle)) < 0) {
if ((ret = drmAgpAlloc(atic->drmFd, atis->gartSize * 1024 * 1024, 0,
NULL, &atis->agpMemHandle)) < 0) {
ErrorF("[agp] Out of memory (%d)\n", ret);
drmAgpRelease(atic->drmFd);
return FALSE;
}
ErrorF("[agp] %d kB allocated with handle 0x%08lx\n",
atis->gartSize*1024, (long)atis->agpMemHandle);
atis->gartSize * 1024, (long)atis->agpMemHandle);
if (drmAgpBind(atic->drmFd, atis->agpMemHandle, atis->gartOffset) < 0) {
ErrorF("[agp] Could not bind\n");
@ -350,30 +318,31 @@ ATIDRIAgpInit(ScreenPtr pScreen)
return FALSE;
/* Initialize radeon/r128 AGP registers */
cntl = MMIO_IN32(mmio, RADEON_REG_AGP_CNTL);
cntl &= ~RADEON_AGP_APER_SIZE_MASK;
cntl = MMIO_IN32(mmio, ATI_REG_AGP_CNTL);
cntl &= ~ATI_AGP_APER_SIZE_MASK;
switch (atis->gartSize) {
case 256: cntl |= RADEON_AGP_APER_SIZE_256MB; break;
case 128: cntl |= RADEON_AGP_APER_SIZE_128MB; break;
case 64: cntl |= RADEON_AGP_APER_SIZE_64MB; break;
case 32: cntl |= RADEON_AGP_APER_SIZE_32MB; break;
case 16: cntl |= RADEON_AGP_APER_SIZE_16MB; break;
case 8: cntl |= RADEON_AGP_APER_SIZE_8MB; break;
case 4: cntl |= RADEON_AGP_APER_SIZE_4MB; break;
case 256: cntl |= ATI_AGP_APER_SIZE_256MB; break;
case 128: cntl |= ATI_AGP_APER_SIZE_128MB; break;
case 64: cntl |= ATI_AGP_APER_SIZE_64MB; break;
case 32: cntl |= ATI_AGP_APER_SIZE_32MB; break;
case 16: cntl |= ATI_AGP_APER_SIZE_16MB; break;
case 8: cntl |= ATI_AGP_APER_SIZE_8MB; break;
case 4: cntl |= ATI_AGP_APER_SIZE_4MB; break;
default:
ErrorF("[agp] Illegal aperture size %d kB\n", atis->gartSize*1024);
ErrorF("[agp] Illegal aperture size %d kB\n", atis->gartSize *
1024);
return FALSE;
}
agpBase = drmAgpBase(atic->drmFd);
MMIO_OUT32(mmio, RADEON_REG_AGP_BASE, agpBase);
MMIO_OUT32(mmio, RADEON_REG_AGP_CNTL, cntl);
MMIO_OUT32(mmio, ATI_REG_AGP_BASE, agpBase);
MMIO_OUT32(mmio, ATI_REG_AGP_CNTL, cntl);
if (!atic->is_radeon) {
/* Disable Rage 128 PCIGART registers */
chunk = MMIO_IN32(mmio, R128_REG_BM_CHUNK_0_VAL);
chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
R128_BM_PM4_RD_FORCE_TO_PCI |
R128_BM_GLOBAL_FORCE_TO_PCI);
R128_BM_PM4_RD_FORCE_TO_PCI |
R128_BM_GLOBAL_FORCE_TO_PCI);
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
/* Ensure AGP GART is used (for now) */
@ -395,14 +364,14 @@ ATIDRIPciInit(ScreenPtr pScreen)
ATIDRIInitGARTValues(pScreen);
ret = drmScatterGatherAlloc(atic->drmFd, atis->gartSize*1024*1024,
ret = drmScatterGatherAlloc(atic->drmFd, atis->gartSize * 1024 * 1024,
&atis->pciMemHandle);
if (ret < 0) {
ErrorF("[pci] Out of memory (%d)\n", ret);
return FALSE;
}
ErrorF("[pci] %d kB allocated with handle 0x%08lx\n",
atis->gartSize*1024, (long)atis->pciMemHandle);
atis->gartSize * 1024, (long)atis->pciMemHandle);
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringStart, atis->ringMapSize,
DRM_SCATTER_GATHER, DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
@ -432,7 +401,8 @@ ATIDRIPciInit(ScreenPtr pScreen)
chunk |= (R128_BM_PTR_FORCE_TO_PCI |
R128_BM_PM4_RD_FORCE_TO_PCI | R128_BM_GLOBAL_FORCE_TO_PCI);
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
/* Ensure PCI GART is used */
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 0);
}
return TRUE;
}
@ -446,29 +416,28 @@ R128DRIKernelInit(ScreenPtr pScreen)
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
drmR128Init drmInfo;
int bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
memset(&drmInfo, 0, sizeof(drmR128Init) );
drmInfo.func = DRM_R128_INIT_CCE;
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
drmInfo.is_pci = !atis->IsAGP;
drmInfo.cce_mode = atis->CCEMode;
drmInfo.is_pci = !atic->is_agp;
drmInfo.cce_mode = R128_PM4_64BM_64VCBM_64INDBM;
drmInfo.cce_secure = TRUE;
drmInfo.ring_size = atis->ringSize*1024*1024;
drmInfo.ring_size = atis->ringSize * 1024 * 1024;
drmInfo.usec_timeout = atis->DMAusecTimeout;
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
/* XXX: pitches are in pixels on r128. */
drmInfo.front_offset = atis->frontOffset;
drmInfo.front_pitch = atis->frontPitch;
drmInfo.front_pitch = atis->frontPitch / (bpp / 8);
drmInfo.back_offset = atis->backOffset;
drmInfo.back_pitch = atis->backPitch;
drmInfo.back_pitch = atis->backPitch / (bpp / 8);
drmInfo.fb_bpp = bpp;
drmInfo.depth_offset = atis->depthOffset;
drmInfo.depth_pitch = atis->depthPitch;
drmInfo.depth_pitch = atis->depthPitch / (bpp / 8);
drmInfo.depth_bpp = bpp;
drmInfo.span_offset = atis->spanOffset;
drmInfo.fb_offset = atis->fbHandle;
@ -502,21 +471,20 @@ RadeonDRIKernelInit(ScreenPtr pScreen)
drmInfo.func = DRM_RADEON_INIT_CP;
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
drmInfo.is_pci = !atis->IsAGP;
drmInfo.cp_mode = atis->CPMode;
drmInfo.gart_size = atis->gartSize*1024*1024;
drmInfo.ring_size = atis->ringSize*1024*1024;
drmInfo.is_pci = !atic->is_agp;
drmInfo.cp_mode = RADEON_CSQ_PRIBM_INDBM;
drmInfo.gart_size = atis->gartSize * 1024 * 1024;
drmInfo.ring_size = atis->ringSize * 1024 * 1024;
drmInfo.usec_timeout = atis->DMAusecTimeout;
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.front_offset = atis->frontOffset;
drmInfo.front_pitch = atis->frontPitch;
drmInfo.back_offset = atis->backOffset;
drmInfo.back_pitch = atis->backPitch;
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.depth_offset = atis->depthOffset;
drmInfo.depth_pitch = atis->depthPitch;
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
drmInfo.fb_offset = atis->fbHandle;
drmInfo.mmio_offset = atis->registerHandle;
@ -547,7 +515,7 @@ ATIDRIBufInit(ScreenPtr pScreen)
else
size = R128_BUFFER_SIZE;
if (atis->IsAGP)
if (atic->is_agp)
type = DRM_AGP_BUFFER;
else
type = DRM_SG_BUFFER;
@ -607,14 +575,14 @@ static void ATIDRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
(newContextType==DRI_2D_CONTEXT)) {
/* Exiting from Block Handler */
if (atis->using_dma)
ATIDMAFlushIndirect(1);
if (atis->dma_started)
ATIFlushIndirect(atis, 1);
}
}
static Bool ATIDRIFinishScreenInit(ScreenPtr pScreen);
/* Initialize the screen-specific data structures for the DRI and the
/* Initialize the screen-specific data structures for the Radeon or
Rage 128. This is the main entry point to the device-specific
initialization code. It calls device-independent DRI functions to
create the DRI data structures and initialize the DRI state. */
@ -630,17 +598,12 @@ ATIDRIScreenInit(ScreenPtr pScreen)
int devSareaSize;
drmSetVersion sv;
/* XXX: Disable DRI clients for unsupported depths */
if (atic->is_radeon) {
atis->CPMode = RADEON_CSQ_PRIBM_INDBM;
}
else {
atis->CCEMode = R128_PM4_64BM_64VCBM_64INDBM;
atis->CCEFifoSize = 64;
if (pScreenPriv->screen->fb[0].depth < 16 ||
pScreenPriv->screen->fb[0].bitsPerPixel == 24) {
ErrorF("DRI unsupported at this depth/bpp, disabling.\n");
return FALSE;
}
atis->IsAGP = FALSE; /* XXX */
atis->agpMode = 1;
atis->gartSize = 8;
atis->ringSize = 1;
@ -674,7 +637,7 @@ ATIDRIScreenInit(ScreenPtr pScreen)
* DRIScreenInit().
*/
pDRIInfo = DRICreateInfoRec();
if (!pDRIInfo)
if (pDRIInfo == NULL)
return FALSE;
atis->pDRIInfo = pDRIInfo;
@ -692,9 +655,8 @@ ATIDRIScreenInit(ScreenPtr pScreen)
pDRIInfo->ddxDriverMajorVersion = 4;
pDRIInfo->ddxDriverMinorVersion = 0;
pDRIInfo->ddxDriverPatchVersion = 0;
/* XXX: RADEON_FB_BASE(pScreenPriv->card); */
pDRIInfo->frameBufferPhysicalAddress =
(unsigned long)pScreenPriv->screen->memory_base;
pScreenPriv->card->attr.address[0] & 0xfc000000;
pDRIInfo->frameBufferSize = pScreenPriv->screen->memory_size;
pDRIInfo->frameBufferStride = pScreenPriv->screen->fb[0].byteStride;
pDRIInfo->ddxDrawableTableEntry = SAREA_MAX_DRAWABLES;
@ -705,12 +667,12 @@ ATIDRIScreenInit(ScreenPtr pScreen)
*/
pDRIInfo->SAREASize = SAREA_MAX;
if (!atic->is_radeon) {
pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
devSareaSize = sizeof(R128SAREAPriv);
} else {
if (atic->is_radeon) {
pDRIInfo->devPrivateSize = sizeof(RADEONDRIRec);
devSareaSize = sizeof(RADEONSAREAPriv);
} else {
pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
devSareaSize = sizeof(R128SAREAPriv);
}
if (sizeof(XF86DRISAREARec) + devSareaSize > SAREA_MAX) {
@ -751,8 +713,8 @@ ATIDRIScreenInit(ScreenPtr pScreen)
/* Add a map for the MMIO registers that will be accessed by any
* DRI-based clients.
*/
atis->registerSize = RADEON_REG_SIZE(atic);
if (drmAddMap(atic->drmFd, RADEON_REG_BASE(pScreenPriv->screen->card),
atis->registerSize = ATI_REG_SIZE(pScreenPriv->screen->card);
if (drmAddMap(atic->drmFd, ATI_REG_BASE(pScreenPriv->screen->card),
atis->registerSize, DRM_REGISTERS, DRM_READ_ONLY,
&atis->registerHandle) < 0) {
ATIDRICloseScreen(pScreen);
@ -765,14 +727,14 @@ ATIDRIScreenInit(ScreenPtr pScreen)
&scratch_int, &scratch_int, &scratch_ptr);
/* Initialize AGP */
if (atis->IsAGP && !ATIDRIAgpInit(pScreen)) {
atis->IsAGP = FALSE;
if (atic->is_agp && !ATIDRIAgpInit(pScreen)) {
atic->is_agp = FALSE;
ErrorF("[agp] AGP failed to initialize; falling back to PCI mode.\n");
ErrorF("[agp] Make sure your kernel's AGP support is loaded and functioning.");
ErrorF("[agp] Make sure your kernel's AGP support is loaded and functioning.\n");
}
/* Initialize PCIGART */
if (!atis->IsAGP && !ATIDRIPciInit(pScreen)) {
if (!atic->is_agp && !ATIDRIPciInit(pScreen)) {
ATIDRICloseScreen(pScreen);
return FALSE;
}
@ -797,9 +759,11 @@ static Bool
R128DRIFinishScreenInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
R128SAREAPrivPtr pSAREAPriv;
R128DRIPtr pR128DRI;
int bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
/* Initialize the kernel data structures */
if (!R128DRIKernelInit(pScreen)) {
@ -816,9 +780,6 @@ R128DRIFinishScreenInit(ScreenPtr pScreen)
/* Initialize IRQ */
ATIDRIIrqInit(pScreen);
/* Initialize and start the CCE if required */
ATIDMAStart(pScreen);
pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
@ -830,15 +791,15 @@ R128DRIFinishScreenInit(ScreenPtr pScreen)
pR128DRI->depth = pScreenPriv->screen->fb[0].depth;
pR128DRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
pR128DRI->IsPCI = !atis->IsAGP;
pR128DRI->IsPCI = !atic->is_agp;
pR128DRI->AGPMode = atis->agpMode;
pR128DRI->frontOffset = atis->frontOffset;
pR128DRI->frontPitch = atis->frontPitch;
pR128DRI->frontPitch = atis->frontPitch / (bpp / 8);
pR128DRI->backOffset = atis->backOffset;
pR128DRI->backPitch = atis->backPitch;
pR128DRI->backPitch = atis->backPitch / (bpp / 8);
pR128DRI->depthOffset = atis->depthOffset;
pR128DRI->depthPitch = atis->depthPitch;
pR128DRI->depthPitch = atis->depthPitch / (bpp / 8);
pR128DRI->spanOffset = atis->spanOffset;
pR128DRI->textureOffset = atis->textureOffset;
pR128DRI->textureSize = atis->textureSize;
@ -894,8 +855,6 @@ RadeonDRIFinishScreenInit(ScreenPtr pScreen)
ErrorF("[drm] Failed to initialize GART heap manager\n");
}
ATIDMAStart(pScreen);
/* Initialize the SAREA private data structure */
pSAREAPriv = (RADEONSAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
@ -908,7 +867,7 @@ RadeonDRIFinishScreenInit(ScreenPtr pScreen)
pRADEONDRI->depth = pScreenPriv->screen->fb[0].depth;
pRADEONDRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
pRADEONDRI->IsPCI = !atis->IsAGP;
pRADEONDRI->IsPCI = !atic->is_agp;
pRADEONDRI->AGPMode = atis->agpMode;
pRADEONDRI->frontOffset = atis->frontOffset;
@ -968,8 +927,6 @@ ATIDRIFinishScreenInit(ScreenPtr pScreen)
}
}
atis->using_dri = TRUE;
return TRUE;
}
@ -985,11 +942,17 @@ ATIDRICloseScreen(ScreenPtr pScreen)
drmRadeonInit drmRadeonInfo;
if (atis->indirectBuffer != NULL) {
ATIDMADispatchIndirect(1);
/* Flush any remaining commands and free indirect buffers.
* Two steps are used because ATIFlushIndirect gets a
* new buffer after discarding.
*/
ATIFlushIndirect(atis, 1);
ATIDRIDispatchIndirect(atis, 1);
xfree(atis->indirectBuffer);
atis->indirectBuffer = NULL;
atis->indirectStart = 0;
}
ATIDMAStop(pScreen);
ATIDRIDMAStop(pScreen);
if (atis->irqEnabled) {
drmCtlUninstHandler(atic->drmFd);
@ -1055,7 +1018,7 @@ ATIDRICloseScreen(ScreenPtr pScreen)
DRIDestroyInfoRec(atis->pDRIInfo);
atis->pDRIInfo = NULL;
}
atis->using_dri = FALSE;
#ifdef GLXEXT
if (atis->pVisualConfigs) {
xfree(atis->pVisualConfigs);
@ -1068,3 +1031,101 @@ ATIDRICloseScreen(ScreenPtr pScreen)
#endif /* GLXEXT */
atic->drmFd = -1;
}
void
ATIDRIDMAStart(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
int ret;
if (atic->is_radeon)
ret = drmCommandNone(atic->drmFd, DRM_RADEON_CP_START);
else
ret = drmCommandNone(atic->drmFd, DRM_R128_CCE_START);
if (ret == 0)
atis->dma_started = TRUE;
else
ErrorF("%s: DMA start returned %d\n", __FUNCTION__, ret);
}
/* Attempts to idle the DMA engine and stops it. Note that the ioctl is the
* same for both R128 and Radeon, so we can just use the name of one of them.
*/
void
ATIDRIDMAStop(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
drmRadeonCPStop stop;
int ret;
stop.flush = 1;
stop.idle = 1;
ret = drmCommandWrite(atic->drmFd, DRM_RADEON_CP_STOP, &stop,
sizeof(drmRadeonCPStop));
if (ret != 0 && errno == EBUSY) {
ErrorF("Failed to idle the DMA engine\n");
stop.idle = 0;
ret = drmCommandWrite(atic->drmFd, DRM_RADEON_CP_STOP, &stop,
sizeof(drmRadeonCPStop));
}
atis->dma_started = FALSE;
}
/* The R128 and Radeon Indirect ioctls differ only in the ioctl number */
void
ATIDRIDispatchIndirect(ATIScreenInfo *atis, Bool discard)
{
ATICardInfo *atic = atis->atic;
drmBufPtr buffer = atis->indirectBuffer->drmBuf;
drmR128Indirect indirect;
int cmd;
indirect.idx = buffer->idx;
indirect.start = atis->indirectStart;
indirect.end = buffer->used;
indirect.discard = discard;
cmd = atic->is_radeon ? DRM_RADEON_INDIRECT : DRM_R128_INDIRECT;
drmCommandWriteRead(atic->drmFd, cmd, &indirect,
sizeof(drmR128Indirect));
}
/* Get an indirect buffer for the DMA 2D acceleration commands */
drmBufPtr
ATIDRIGetBuffer(ATIScreenInfo *atis)
{
ATICardInfo *atic = atis->atic;
drmDMAReq dma;
drmBufPtr buf = NULL;
int indx = 0;
int size = 0;
int ret;
dma.context = atis->serverContext;
dma.send_count = 0;
dma.send_list = NULL;
dma.send_sizes = NULL;
dma.flags = 0;
dma.request_count = 1;
if (atis->atic->is_radeon)
dma.request_size = RADEON_BUFFER_SIZE;
else
dma.request_size = R128_BUFFER_SIZE;
dma.request_list = &indx;
dma.request_sizes = &size;
dma.granted_count = 0;
do {
ret = drmDMA(atic->drmFd, &dma);
} while (ret != 0);
buf = &atis->buffers->list[indx];
buf->used = 0;
return buf;
}

View File

@ -0,0 +1,597 @@
/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
* radeon_cp.c -- CP support for Radeon -*- linux-c -*-
*
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Fremont, California.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
*/
/* CCE microcode (from ATI) */
#include "ati.h"
CARD32 r128_cce_microcode[] = {
0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0,
1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0,
599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1,
11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11,
262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28,
1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9,
30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656,
1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1,
15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071,
12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2,
46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1,
459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1,
18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1,
15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2,
268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1,
15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82,
1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729,
3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008,
1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0,
15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1,
180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1,
114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0,
33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370,
1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1,
14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793,
1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1,
198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1,
114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1,
1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1,
1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894,
16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14,
174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1,
33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1,
33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1,
409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
CARD32 radeon_cp_microcode[][2] = {
{ 0x21007000, 0000000000 },
{ 0x20007000, 0000000000 },
{ 0x000000b4, 0x00000004 },
{ 0x000000b8, 0x00000004 },
{ 0x6f5b4d4c, 0000000000 },
{ 0x4c4c427f, 0000000000 },
{ 0x5b568a92, 0000000000 },
{ 0x4ca09c6d, 0000000000 },
{ 0xad4c4c4c, 0000000000 },
{ 0x4ce1af3d, 0000000000 },
{ 0xd8afafaf, 0000000000 },
{ 0xd64c4cdc, 0000000000 },
{ 0x4cd10d10, 0000000000 },
{ 0x000f0000, 0x00000016 },
{ 0x362f242d, 0000000000 },
{ 0x00000012, 0x00000004 },
{ 0x000f0000, 0x00000016 },
{ 0x362f282d, 0000000000 },
{ 0x000380e7, 0x00000002 },
{ 0x04002c97, 0x00000002 },
{ 0x000f0001, 0x00000016 },
{ 0x333a3730, 0000000000 },
{ 0x000077ef, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000021, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00000017, 0x00000004 },
{ 0x0003802b, 0x00000002 },
{ 0x040067e0, 0x00000002 },
{ 0x00000017, 0x00000004 },
{ 0x000077e0, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x000037e1, 0x00000002 },
{ 0x040067e1, 0x00000006 },
{ 0x000077e0, 0x00000002 },
{ 0x000077e1, 0x00000002 },
{ 0x000077e1, 0x00000006 },
{ 0xffffffff, 0000000000 },
{ 0x10000000, 0000000000 },
{ 0x0003802b, 0x00000002 },
{ 0x040067e0, 0x00000006 },
{ 0x00007675, 0x00000002 },
{ 0x00007676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0003802c, 0x00000002 },
{ 0x04002676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0000002f, 0x00000018 },
{ 0x0000002f, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x00000030, 0x00000018 },
{ 0x00000030, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x01605000, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00098000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x64c0603e, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00080000, 0x00000016 },
{ 0000000000, 0000000000 },
{ 0x0400251d, 0x00000002 },
{ 0x00007580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x04002580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x00000049, 0x00000004 },
{ 0x00005000, 0000000000 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x00019000, 0x00000002 },
{ 0x00011055, 0x00000014 },
{ 0x00000055, 0x00000012 },
{ 0x0400250f, 0x00000002 },
{ 0x0000504f, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007565, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000058, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x01e655b4, 0x00000002 },
{ 0x4401b0e4, 0x00000002 },
{ 0x01c110e4, 0x00000002 },
{ 0x26667066, 0x00000018 },
{ 0x040c2565, 0x00000002 },
{ 0x00000066, 0x00000018 },
{ 0x04002564, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x0000005d, 0x00000004 },
{ 0x00401069, 0x00000008 },
{ 0x00101000, 0x00000002 },
{ 0x000d80ff, 0x00000002 },
{ 0x0080006c, 0x00000008 },
{ 0x000f9000, 0x00000002 },
{ 0x000e00ff, 0x00000002 },
{ 0000000000, 0x00000006 },
{ 0x0000008f, 0x00000018 },
{ 0x0000005b, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007576, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00009000, 0x00000002 },
{ 0x00041000, 0x00000002 },
{ 0x0c00350e, 0x00000002 },
{ 0x00049000, 0x00000002 },
{ 0x00051000, 0x00000002 },
{ 0x01e785f8, 0x00000002 },
{ 0x00200000, 0x00000002 },
{ 0x0060007e, 0x0000000c },
{ 0x00007563, 0x00000002 },
{ 0x006075f0, 0x00000021 },
{ 0x20007073, 0x00000004 },
{ 0x00005073, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00007576, 0x00000002 },
{ 0x00007577, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x0000750f, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00600083, 0x0000000c },
{ 0x006075f0, 0x00000021 },
{ 0x000075f8, 0x00000002 },
{ 0x00000083, 0x00000004 },
{ 0x000a750e, 0x00000002 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x0020750f, 0x00000002 },
{ 0x00600086, 0x00000004 },
{ 0x00007570, 0x00000002 },
{ 0x00007571, 0x00000002 },
{ 0x00007572, 0x00000006 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00005000, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00007568, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000095, 0x0000000c },
{ 0x00058000, 0x00000002 },
{ 0x0c607562, 0x00000002 },
{ 0x00000097, 0x00000004 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x00600096, 0x00000004 },
{ 0x400070e5, 0000000000 },
{ 0x000380e6, 0x00000002 },
{ 0x040025c5, 0x00000002 },
{ 0x000380e5, 0x00000002 },
{ 0x000000a8, 0x0000001c },
{ 0x000650aa, 0x00000018 },
{ 0x040025bb, 0x00000002 },
{ 0x000610ab, 0x00000018 },
{ 0x040075bc, 0000000000 },
{ 0x000075bb, 0x00000002 },
{ 0x000075bc, 0000000000 },
{ 0x00090000, 0x00000006 },
{ 0x00090000, 0x00000002 },
{ 0x000d8002, 0x00000006 },
{ 0x00007832, 0x00000002 },
{ 0x00005000, 0x00000002 },
{ 0x000380e7, 0x00000002 },
{ 0x04002c97, 0x00000002 },
{ 0x00007820, 0x00000002 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x01200000, 0x00000002 },
{ 0x20077000, 0x00000002 },
{ 0x01200000, 0x00000002 },
{ 0x20007000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x0120751b, 0x00000002 },
{ 0x8040750a, 0x00000002 },
{ 0x8040750b, 0x00000002 },
{ 0x00110000, 0x00000002 },
{ 0x000380e5, 0x00000002 },
{ 0x000000c6, 0x0000001c },
{ 0x000610ab, 0x00000018 },
{ 0x844075bd, 0x00000002 },
{ 0x000610aa, 0x00000018 },
{ 0x840075bb, 0x00000002 },
{ 0x000610ab, 0x00000018 },
{ 0x844075bc, 0x00000002 },
{ 0x000000c9, 0x00000004 },
{ 0x804075bd, 0x00000002 },
{ 0x800075bb, 0x00000002 },
{ 0x804075bc, 0x00000002 },
{ 0x00108000, 0x00000002 },
{ 0x01400000, 0x00000002 },
{ 0x006000cd, 0x0000000c },
{ 0x20c07000, 0x00000020 },
{ 0x000000cf, 0x00000012 },
{ 0x00800000, 0x00000006 },
{ 0x0080751d, 0x00000006 },
{ 0000000000, 0000000000 },
{ 0x0000775c, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460275d, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x01e00830, 0x00000002 },
{ 0x21007000, 0000000000 },
{ 0x6464614d, 0000000000 },
{ 0x69687420, 0000000000 },
{ 0x00000073, 0000000000 },
{ 0000000000, 0000000000 },
{ 0x00005000, 0x00000002 },
{ 0x000380d0, 0x00000002 },
{ 0x040025e0, 0x00000002 },
{ 0x000075e1, 0000000000 },
{ 0x00000001, 0000000000 },
{ 0x000380e0, 0x00000002 },
{ 0x04002394, 0x00000002 },
{ 0x00005000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0x00000008, 0000000000 },
{ 0x00000004, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
};
CARD32 r200_cp_microcode[][2] = {
{ 0x21007000, 0000000000 },
{ 0x20007000, 0000000000 },
{ 0x000000ab, 0x00000004 },
{ 0x000000af, 0x00000004 },
{ 0x66544a49, 0000000000 },
{ 0x49494174, 0000000000 },
{ 0x54517d83, 0000000000 },
{ 0x498d8b64, 0000000000 },
{ 0x49494949, 0000000000 },
{ 0x49da493c, 0000000000 },
{ 0x49989898, 0000000000 },
{ 0xd34949d5, 0000000000 },
{ 0x9dc90e11, 0000000000 },
{ 0xce9b9b9b, 0000000000 },
{ 0x000f0000, 0x00000016 },
{ 0x352e232c, 0000000000 },
{ 0x00000013, 0x00000004 },
{ 0x000f0000, 0x00000016 },
{ 0x352e272c, 0000000000 },
{ 0x000f0001, 0x00000016 },
{ 0x3239362f, 0000000000 },
{ 0x000077ef, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00061000, 0x00000002 },
{ 0x00000020, 0x0000001a },
{ 0x00004000, 0x0000001e },
{ 0x00000016, 0x00000004 },
{ 0x0003802a, 0x00000002 },
{ 0x040067e0, 0x00000002 },
{ 0x00000016, 0x00000004 },
{ 0x000077e0, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x000037e1, 0x00000002 },
{ 0x040067e1, 0x00000006 },
{ 0x000077e0, 0x00000002 },
{ 0x000077e1, 0x00000002 },
{ 0x000077e1, 0x00000006 },
{ 0xffffffff, 0000000000 },
{ 0x10000000, 0000000000 },
{ 0x0003802a, 0x00000002 },
{ 0x040067e0, 0x00000006 },
{ 0x00007675, 0x00000002 },
{ 0x00007676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0003802b, 0x00000002 },
{ 0x04002676, 0x00000002 },
{ 0x00007677, 0x00000002 },
{ 0x00007678, 0x00000006 },
{ 0x0000002e, 0x00000018 },
{ 0x0000002e, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x0000002f, 0x00000018 },
{ 0x0000002f, 0x00000018 },
{ 0000000000, 0x00000006 },
{ 0x01605000, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00098000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x64c0603d, 0x00000004 },
{ 0x00080000, 0x00000016 },
{ 0000000000, 0000000000 },
{ 0x0400251d, 0x00000002 },
{ 0x00007580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x04002580, 0x00000002 },
{ 0x00067581, 0x00000002 },
{ 0x00000046, 0x00000004 },
{ 0x00005000, 0000000000 },
{ 0x00061000, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x00019000, 0x00000002 },
{ 0x00011055, 0x00000014 },
{ 0x00000055, 0x00000012 },
{ 0x0400250f, 0x00000002 },
{ 0x0000504a, 0x00000004 },
{ 0x00007565, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000051, 0x00000004 },
{ 0x01e655b4, 0x00000002 },
{ 0x4401b0dc, 0x00000002 },
{ 0x01c110dc, 0x00000002 },
{ 0x2666705d, 0x00000018 },
{ 0x040c2565, 0x00000002 },
{ 0x0000005d, 0x00000018 },
{ 0x04002564, 0x00000002 },
{ 0x00007566, 0x00000002 },
{ 0x00000054, 0x00000004 },
{ 0x00401060, 0x00000008 },
{ 0x00101000, 0x00000002 },
{ 0x000d80ff, 0x00000002 },
{ 0x00800063, 0x00000008 },
{ 0x000f9000, 0x00000002 },
{ 0x000e00ff, 0x00000002 },
{ 0000000000, 0x00000006 },
{ 0x00000080, 0x00000018 },
{ 0x00000054, 0x00000004 },
{ 0x00007576, 0x00000002 },
{ 0x00065000, 0x00000002 },
{ 0x00009000, 0x00000002 },
{ 0x00041000, 0x00000002 },
{ 0x0c00350e, 0x00000002 },
{ 0x00049000, 0x00000002 },
{ 0x00051000, 0x00000002 },
{ 0x01e785f8, 0x00000002 },
{ 0x00200000, 0x00000002 },
{ 0x00600073, 0x0000000c },
{ 0x00007563, 0x00000002 },
{ 0x006075f0, 0x00000021 },
{ 0x20007068, 0x00000004 },
{ 0x00005068, 0x00000004 },
{ 0x00007576, 0x00000002 },
{ 0x00007577, 0x00000002 },
{ 0x0000750e, 0x00000002 },
{ 0x0000750f, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00600076, 0x0000000c },
{ 0x006075f0, 0x00000021 },
{ 0x000075f8, 0x00000002 },
{ 0x00000076, 0x00000004 },
{ 0x000a750e, 0x00000002 },
{ 0x0020750f, 0x00000002 },
{ 0x00600079, 0x00000004 },
{ 0x00007570, 0x00000002 },
{ 0x00007571, 0x00000002 },
{ 0x00007572, 0x00000006 },
{ 0x00005000, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00007568, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x00000084, 0x0000000c },
{ 0x00058000, 0x00000002 },
{ 0x0c607562, 0x00000002 },
{ 0x00000086, 0x00000004 },
{ 0x00600085, 0x00000004 },
{ 0x400070dd, 0000000000 },
{ 0x000380dd, 0x00000002 },
{ 0x00000093, 0x0000001c },
{ 0x00065095, 0x00000018 },
{ 0x040025bb, 0x00000002 },
{ 0x00061096, 0x00000018 },
{ 0x040075bc, 0000000000 },
{ 0x000075bb, 0x00000002 },
{ 0x000075bc, 0000000000 },
{ 0x00090000, 0x00000006 },
{ 0x00090000, 0x00000002 },
{ 0x000d8002, 0x00000006 },
{ 0x00005000, 0x00000002 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x00007821, 0x00000002 },
{ 0x00007800, 0000000000 },
{ 0x01665000, 0x00000002 },
{ 0x000a0000, 0x00000002 },
{ 0x000671cc, 0x00000002 },
{ 0x0286f1cd, 0x00000002 },
{ 0x000000a3, 0x00000010 },
{ 0x21007000, 0000000000 },
{ 0x000000aa, 0x0000001c },
{ 0x00065000, 0x00000002 },
{ 0x000a0000, 0x00000002 },
{ 0x00061000, 0x00000002 },
{ 0x000b0000, 0x00000002 },
{ 0x38067000, 0x00000002 },
{ 0x000a00a6, 0x00000004 },
{ 0x20007000, 0000000000 },
{ 0x01200000, 0x00000002 },
{ 0x20077000, 0x00000002 },
{ 0x01200000, 0x00000002 },
{ 0x20007000, 0000000000 },
{ 0x00061000, 0x00000002 },
{ 0x0120751b, 0x00000002 },
{ 0x8040750a, 0x00000002 },
{ 0x8040750b, 0x00000002 },
{ 0x00110000, 0x00000002 },
{ 0x000380dd, 0x00000002 },
{ 0x000000bd, 0x0000001c },
{ 0x00061096, 0x00000018 },
{ 0x844075bd, 0x00000002 },
{ 0x00061095, 0x00000018 },
{ 0x840075bb, 0x00000002 },
{ 0x00061096, 0x00000018 },
{ 0x844075bc, 0x00000002 },
{ 0x000000c0, 0x00000004 },
{ 0x804075bd, 0x00000002 },
{ 0x800075bb, 0x00000002 },
{ 0x804075bc, 0x00000002 },
{ 0x00108000, 0x00000002 },
{ 0x01400000, 0x00000002 },
{ 0x006000c4, 0x0000000c },
{ 0x20c07000, 0x00000020 },
{ 0x000000c6, 0x00000012 },
{ 0x00800000, 0x00000006 },
{ 0x0080751d, 0x00000006 },
{ 0x000025bb, 0x00000002 },
{ 0x000040c0, 0x00000004 },
{ 0x0000775c, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460275d, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x00007999, 0x00000002 },
{ 0x00a05000, 0x00000002 },
{ 0x00661000, 0x00000002 },
{ 0x0460299b, 0x00000020 },
{ 0x00004000, 0000000000 },
{ 0x01e00830, 0x00000002 },
{ 0x21007000, 0000000000 },
{ 0x00005000, 0x00000002 },
{ 0x00038042, 0x00000002 },
{ 0x040025e0, 0x00000002 },
{ 0x000075e1, 0000000000 },
{ 0x00000001, 0000000000 },
{ 0x000380d9, 0x00000002 },
{ 0x04007394, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
{ 0000000000, 0000000000 },
};

File diff suppressed because it is too large Load Diff

950
hw/kdrive/ati/ati_video.c Normal file
View File

@ -0,0 +1,950 @@
/*
* 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;
}

View File

@ -0,0 +1,589 @@
/*
* Copyright © 2003 Eric Anholt, Anders Carlsson
*
* 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.
*/
/* $Header$ */
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_draw.h"
extern ATIScreenInfo *accel_atis;
extern CARD8 ATIBltRop[16];
static int src_pitch;
static int src_offset;
static int src_bpp;
int widths[2] = {1,1};
int heights[2] = {1,1};
Bool is_repeat;
struct blendinfo {
Bool dst_alpha;
Bool src_alpha;
CARD32 blendctl;
};
static struct blendinfo R128BlendOp[] = {
/* Clear */
{0, 0, R128_SBLEND_ZERO | R128_DBLEND_ZERO},
/* Src */
{0, 0, R128_SBLEND_ONE | R128_DBLEND_ZERO},
/* Dst */
{0, 0, R128_SBLEND_ZERO | R128_DBLEND_ONE},
/* Over */
{0, 1, R128_SBLEND_ONE | R128_DBLEND_INV_SRC_ALPHA},
/* OverReverse */
{1, 0, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_ONE},
/* In */
{1, 0, R128_SBLEND_DST_ALPHA | R128_DBLEND_ZERO},
/* InReverse */
{0, 1, R128_SBLEND_ZERO | R128_DBLEND_SRC_ALPHA},
/* Out */
{1, 0, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_ZERO},
/* OutReverse */
{0, 1, R128_SBLEND_ZERO | R128_DBLEND_INV_SRC_ALPHA},
/* Atop */
{1, 1, R128_SBLEND_DST_ALPHA | R128_DBLEND_INV_SRC_ALPHA},
/* AtopReverse */
{1, 1, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_SRC_ALPHA},
/* Xor */
{1, 1, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_INV_SRC_ALPHA},
/* Add */
{0, 0, R128_SBLEND_ONE | R128_DBLEND_ONE},
};
static Bool
R128GetDatatypePict(CARD32 format, CARD32 *type)
{
switch (format) {
case PICT_a1r5g5b5:
*type = R128_DATATYPE_ARGB1555;
return TRUE;
case PICT_r5g6b5:
*type = R128_DATATYPE_RGB565;
return TRUE;
case PICT_a8r8g8b8:
*type = R128_DATATYPE_ARGB8888;
return TRUE;
default:
return FALSE;
}
}
Bool
R128PrepareBlend(int op, PicturePtr pSrcPicture, PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
CARD32 dstDatatype, srcDatatype;
RING_LOCALS;
CARD32 xinc, yinc, dst_pitch_offset;
accel_atis = atis;
src_offset = (CARD8 *)pSrc->devPrivate.ptr -
pScreenPriv->screen->memory_base;
src_pitch = pSrc->devKind;
src_bpp = pSrc->drawable.bitsPerPixel;
is_repeat = pSrcPicture->repeat;
if (op >= sizeof(R128BlendOp)/sizeof(R128BlendOp[0]))
ATI_FALLBACK(("Unsupported op 0x%x\n", op));
if (pSrcPicture->repeat && (pSrc->drawable.width != 1 ||
pSrc->drawable.height != 1))
ATI_FALLBACK(("repeat unsupported\n"));
if (pSrcPicture->transform != NULL)
ATI_FALLBACK(("transform unsupported\n"));
if (!R128GetDatatypePict(pDstPicture->format, &dstDatatype))
ATI_FALLBACK(("Unsupported dest format 0x%x\n",
pDstPicture->format));
if (!R128GetDatatypePict(pSrcPicture->format, &srcDatatype))
ATI_FALLBACK(("Unsupported src format 0x%x\n",
pSrcPicture->format));
if (src_pitch % src_bpp != 0)
ATI_FALLBACK(("Bad src pitch 0x%x\n", src_pitch));
if (!ATIGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
return FALSE;
if (is_repeat) {
xinc = 0;
yinc = 0;
} else {
xinc = 65536;
yinc = 65536;
}
BEGIN_DMA(18);
OUT_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset);
OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL,
ATI_GMC_DST_PITCH_OFFSET_CNTL |
ATI_GMC_BRUSH_SOLID_COLOR |
(dstDatatype << 8) |
ATI_GMC_SRC_DATATYPE_COLOR |
(ATIBltRop[GXcopy] << 16) |
ATI_DP_SRC_SOURCE_MEMORY |
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_SCALE_PIX_REPLICATE |
R128BlendOp[op].blendctl |
R128_TEX_MAP_ALPHA_IN_TEXTURE);
OUT_REG(R128_REG_TEX_CNTL_C, R128_ALPHA_ENABLE | R128_TEX_CACHE_FLUSH);
OUT_REG(R128_REG_SCALE_3D_DATATYPE, srcDatatype);
/* R128_REG_SCALE_PITCH,
* R128_REG_SCALE_X_INC,
* R128_REG_SCALE_Y_INC,
* R128_REG_SCALE_HACC
* R128_REG_SCALE_VACC */
OUT_RING(DMA_PACKET0(R128_REG_SCALE_PITCH, 5));
OUT_RING(src_pitch / src_bpp);
OUT_RING(xinc);
OUT_RING(yinc);
OUT_RING(0x0);
OUT_RING(0x0);
END_DMA();
return TRUE;
}
void
R128Blend(int srcX, int srcY, int dstX, int dstY, int width, int height)
{
ATIScreenInfo *atis = accel_atis;
RING_LOCALS;
if (is_repeat) {
srcX = 0;
srcY = 0;
}
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((height << 16) | width);
OUT_RING(src_offset + srcY * src_pitch + srcX * (src_bpp >> 3));
/* 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((height << 16) | width);
END_DMA();
}
void
R128DoneBlend(void)
{
}
static Bool
R128CheckCompositeTexture(PicturePtr pPict)
{
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
if (w > (1 << 10) || h > (1 << 10))
ATI_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h));
if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0))
ATI_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h));
switch (pPict->format) {
case PICT_a8:
case PICT_a1r5g5b5:
case PICT_a4r4g4b4:
case PICT_r5g6b5:
case PICT_a8r8g8b8:
break;
default:
ATI_FALLBACK(("Unsupported picture format 0x%x\n",
pPict->format));
}
return TRUE;
}
Bool
R128CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture)
{
CARD32 dstDatatype;
if (op >= sizeof(R128BlendOp)/sizeof(R128BlendOp[0]))
ATI_FALLBACK(("Unsupported op 0x%x\n", op));
if (op == PictOpIn || op == PictOpOut || op == PictOpAtopReverse ||
op == PictOpXor)
if (op != PictOpOver)
ATI_FALLBACK(("Something's wacky with these ops\n"));
if (pSrcPicture->transform)
ATI_FALLBACK(("Source transform unsupported.\n"));
if (pMaskPicture && pMaskPicture->transform)
ATI_FALLBACK(("Mask transform unsupported.\n"));
if (pDstPicture->format == PICT_a8) {
if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha ||
pMaskPicture != NULL)
ATI_FALLBACK(("alpha blending unsupported with "
"A8 dst?\n"));
} else if (!R128GetDatatypePict(pDstPicture->format, &dstDatatype)) {
ATI_FALLBACK(("Unsupported dest format 0x%x\n",
pDstPicture->format));
}
if (pMaskPicture != NULL && pMaskPicture->componentAlpha &&
R128BlendOp[op].src_alpha)
ATI_FALLBACK(("Component alpha not supported with source alpha "
"blending.\n"));
if (!R128CheckCompositeTexture(pSrcPicture))
return FALSE;
if (pMaskPicture != NULL && !R128CheckCompositeTexture(pMaskPicture))
return FALSE;
return TRUE;
}
static Bool
R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, CARD32 *txsize,
CARD32 *tex_cntl_c)
{
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
int bytepp, shift, l2w, l2h, l2p;
int pitch;
pitch = pPix->devKind;
if ((pitch & (pitch - 1)) != 0)
ATI_FALLBACK(("NPOT pitch 0x%x unsupported\n", pitch));
switch (pPict->format) {
case PICT_a8:
/* DATATYPE_RGB8 appears to expand the value into the alpha
* channel like we want. We then blank out the R,G,B channels
* as necessary using the combiners.
*/
*tex_cntl_c = R128_DATATYPE_RGB8 << R128_TEX_DATATYPE_SHIFT;
bytepp = 1;
break;
case PICT_a1r5g5b5:
*tex_cntl_c = R128_DATATYPE_ARGB1555 << R128_TEX_DATATYPE_SHIFT;
bytepp = 2;
break;
case PICT_a4r4g4b4:
*tex_cntl_c = R128_DATATYPE_ARGB4444 << R128_TEX_DATATYPE_SHIFT;
bytepp = 2;
break;
case PICT_r5g6b5:
*tex_cntl_c = R128_DATATYPE_RGB565 << R128_TEX_DATATYPE_SHIFT;
bytepp = 2;
break;
case PICT_a8r8g8b8:
*tex_cntl_c = R128_DATATYPE_ARGB8888 << R128_TEX_DATATYPE_SHIFT;
bytepp = 4;
break;
default:
return FALSE;
}
*tex_cntl_c |= R128_MIP_MAP_DISABLE;
if (unit == 0)
shift = 0;
else {
shift = 16;
*tex_cntl_c |= R128_SEC_SELECT_SEC_ST;
}
if (w == 1)
l2w = 0;
else
l2w = ATILog2(w - 1) + 1;
if (h == 1)
l2h = 0;
else
l2h = ATILog2(h - 1) + 1;
l2p = ATILog2(pPix->devKind / bytepp);
if (pPict->repeat && w == 1 && h == 1)
l2p = 0;
else if (pPict->repeat && l2p != l2w)
ATI_FALLBACK(("Repeat not supported for pitch != width\n"));
l2w = l2p;
widths[unit] = 1 << l2w;
heights[unit] = 1 << l2h;
*txsize |= l2p << (R128_TEX_PITCH_SHIFT + shift);
*txsize |= ((l2w > l2h) ? l2w : l2h) << (R128_TEX_SIZE_SHIFT + shift);
*txsize |= l2h << (R128_TEX_HEIGHT_SHIFT + shift);
return TRUE;
}
Bool
R128PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
CARD32 txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype;
CARD32 dst_pitch_offset, color_factor, in_color_factor;
int i;
RING_LOCALS;
accel_atis = atis;
if (pDstPicture->format == PICT_a8)
dstDatatype = R128_DATATYPE_Y8;
else
R128GetDatatypePict(pDstPicture->format, &dstDatatype);
if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c))
return FALSE;
if (pMask != NULL && !R128TextureSetup(pMaskPicture, pMask, 1, &txsize,
&sec_tex_cntl_c))
return FALSE;
if (!ATIGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
return FALSE;
BEGIN_DMA(12);
OUT_REG(R128_REG_SCALE_3D_CNTL,
R128_SCALE_3D_TEXMAP_SHADE |
R128_SCALE_PIX_REPLICATE |
R128_TEX_CACHE_SPLIT |
R128_TEX_MAP_ALPHA_IN_TEXTURE |
R128_TEX_CACHE_LINE_SIZE_4QW);
OUT_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset);
OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL,
ATI_GMC_DST_PITCH_OFFSET_CNTL |
ATI_GMC_BRUSH_SOLID_COLOR |
(dstDatatype << 8) |
ATI_GMC_SRC_DATATYPE_COLOR |
(ATIBltRop[GXcopy] << 16) |
ATI_DP_SRC_SOURCE_MEMORY |
R128_GMC_3D_FCN_EN |
ATI_GMC_CLR_CMP_CNTL_DIS |
R128_GMC_AUX_CLIP_DIS |
ATI_GMC_WR_MSK_DIS);
OUT_REG(R128_REG_MISC_3D_STATE_CNTL,
R128_MISC_SCALE_3D_TEXMAP_SHADE |
R128_MISC_SCALE_PIX_REPLICATE |
R128_ALPHA_COMB_ADD_CLAMP |
R128BlendOp[op].blendctl);
OUT_REG(R128_REG_TEX_CNTL_C,
R128_TEXMAP_ENABLE |
((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) |
R128_ALPHA_ENABLE |
R128_TEX_CACHE_FLUSH);
OUT_REG(R128_REG_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI);
END_DMA();
/* IN operator: Without a mask, only the first texture unit is enabled.
* With a mask, we put the source in the first unit and have it pass
* through as input to the 2nd. The 2nd unit takes the incoming source
* pixel and modulates it with either the alpha or each of the channels
* in the mask, depending on componentAlpha.
*/
BEGIN_DMA(15);
/* R128_REG_PRIM_TEX_CNTL_C,
* R128_REG_PRIM_TEXTURE_COMBINE_CNTL_C,
* R128_REG_TEX_SIZE_PITCH_C,
* R128_REG_PRIM_TEX_0_OFFSET_C - R128_REG_PRIM_TEX_10_OFFSET_C
*/
OUT_RING(DMA_PACKET0(R128_REG_PRIM_TEX_CNTL_C, 14));
OUT_RING(prim_tex_cntl_c);
/* If this is the only stage and the dest is a8, route the alpha result
* to the color (red channel, in particular), too. Otherwise, be sure
* to zero out color channels of an a8 source.
*/
if (pMaskPicture == NULL && pDstPicture->format == PICT_a8)
color_factor = R128_COLOR_FACTOR_ALPHA;
else if (pSrcPicture->format == PICT_a8)
color_factor = R128_COLOR_FACTOR_CONST_COLOR;
else
color_factor = R128_COLOR_FACTOR_TEX;
OUT_RING(R128_COMB_COPY |
color_factor |
R128_INPUT_FACTOR_INT_COLOR |
R128_COMB_ALPHA_DIS |
R128_ALPHA_FACTOR_TEX_ALPHA |
R128_INP_FACTOR_A_INT_ALPHA);
OUT_RING(txsize);
/* We could save some output by only writing the offset register that
* will actually be used. On the other hand, this is easy.
*/
for (i = 0; i <= 10; i++)
OUT_RING(((CARD8 *)pSrc->devPrivate.ptr -
pScreenPriv->screen->memory_base));
END_DMA();
if (pMask != NULL) {
BEGIN_DMA(14);
/* R128_REG_SEC_TEX_CNTL_C,
* R128_REG_SEC_TEXTURE_COMBINE_CNTL_C,
* R128_REG_SEC_TEX_0_OFFSET_C - R128_REG_SEC_TEX_10_OFFSET_C
*/
OUT_RING(DMA_PACKET0(R128_REG_SEC_TEX_CNTL_C, 13));
OUT_RING(sec_tex_cntl_c);
/* XXX: Need to check with keithp to see if component alpha a8
* masks should act as non-CA, or if they should expand the RGB
* channels as 0.
*/
if (pDstPicture->format == PICT_a8) {
color_factor = R128_COLOR_FACTOR_ALPHA;
in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA;
} else if (pMaskPicture->componentAlpha) {
color_factor = R128_COLOR_FACTOR_TEX;
in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
} else {
color_factor = R128_COLOR_FACTOR_ALPHA;
in_color_factor = R128_INPUT_FACTOR_PREV_COLOR;
}
OUT_RING(R128_COMB_MODULATE |
color_factor |
in_color_factor |
R128_COMB_ALPHA_MODULATE |
R128_ALPHA_FACTOR_TEX_ALPHA |
R128_INP_FACTOR_A_PREV_ALPHA);
for (i = 0; i <= 10; i++)
OUT_RING(((CARD8 *)pMask->devPrivate.ptr -
pScreenPriv->screen->memory_base));
END_DMA();
}
return TRUE;
}
union intfloat {
float f;
CARD32 i;
};
struct blend_vertex {
union intfloat x, y, z, w;
union intfloat s0, t0;
union intfloat s1, t1;
};
#define VTX_RING_COUNT 8
#define VTX_OUT(vtx) \
do { \
OUT_RING(vtx.x.i); \
OUT_RING(vtx.y.i); \
OUT_RING(vtx.z.i); \
OUT_RING(vtx.w.i); \
OUT_RING(vtx.s0.i); \
OUT_RING(vtx.t0.i); \
OUT_RING(vtx.s1.i); \
OUT_RING(vtx.t1.i); \
} while (0)
void
R128Composite(int srcX, int srcY, int maskX, int maskY, int dstX, int dstY,
int w, int h)
{
ATIScreenInfo *atis = accel_atis;
struct blend_vertex vtx[4];
int i;
RING_LOCALS;
/*ErrorF("R128Composite (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n",
srcX, srcY, maskX, maskY,dstX, dstY, w, h);*/
vtx[0].x.f = dstX;
vtx[0].y.f = dstY;
vtx[0].z.f = 0.0;
vtx[0].w.f = 1.0;
vtx[0].s0.f = srcX;
vtx[0].t0.f = srcY;
vtx[0].s1.f = maskX;
vtx[0].t1.f = maskY;
vtx[1].x.f = dstX;
vtx[1].y.f = dstY + h;
vtx[1].z.f = 0.0;
vtx[1].w.f = 1.0;
vtx[1].s0.f = srcX;
vtx[1].t0.f = srcY + h;
vtx[1].s1.f = maskX;
vtx[1].t1.f = maskY + h;
vtx[2].x.f = dstX + w;
vtx[2].y.f = dstY + h;
vtx[2].z.f = 0.0;
vtx[2].w.f = 1.0;
vtx[2].s0.f = srcX + w;
vtx[2].t0.f = srcY + h;
vtx[2].s1.f = maskX + w;
vtx[2].t1.f = maskY + h;
vtx[3].x.f = dstX + w;
vtx[3].y.f = dstY;
vtx[3].z.f = 0.0;
vtx[3].w.f = 1.0;
vtx[3].s0.f = srcX + w;
vtx[3].t0.f = srcY;
vtx[3].s1.f = maskX + w;
vtx[3].t1.f = maskY;
for (i = 0; i < 4; i++) {
vtx[i].x.f += 0.0;
vtx[i].y.f += 0.125;
vtx[i].s0.f /= widths[0];
vtx[i].t0.f /= heights[0];
vtx[i].s1.f /= widths[1];
vtx[i].t1.f /= heights[1];
}
BEGIN_DMA(3 + 4 * VTX_RING_COUNT);
OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_3D_RNDR_GEN_PRIM,
2 + 4 * VTX_RING_COUNT));
OUT_RING(R128_CCE_VC_FRMT_RHW |
R128_CCE_VC_FRMT_S_T |
R128_CCE_VC_FRMT_S2_T2);
OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN |
R128_CCE_VC_CNTL_PRIM_WALK_RING |
(4 << R128_CCE_VC_CNTL_NUM_SHIFT));
VTX_OUT(vtx[0]);
VTX_OUT(vtx[1]);
VTX_OUT(vtx[2]);
VTX_OUT(vtx[3]);
END_DMA();
}
void
R128DoneComposite(void)
{
}

View File

@ -28,100 +28,369 @@
#endif
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_draw.h"
#include "radeon_common.h"
#include "r128_common.h"
#include "ati_sarea.h"
#define TAG(x) x##DMA
#define LOCALS RING_LOCALS; \
(void)atic;
#define BEGIN(x) BEGIN_RING(x * 2)
#define OUT_REG(reg, val) OUT_RING_REG(reg, val)
#define END() ADVANCE_RING()
extern ATIScreenInfo *accel_atis;
static CARD32 RadeonBlendOp[] = {
/* Clear */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_ZERO,
/* Src */
RADEON_SRC_BLEND_GL_ONE | RADEON_DST_BLEND_GL_ZERO,
/* Dst */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_ONE,
/* Over */
RADEON_SRC_BLEND_GL_ONE | RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA,
/* OverReverse */
RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | RADEON_DST_BLEND_GL_ONE,
/* In */
RADEON_SRC_BLEND_GL_DST_ALPHA | RADEON_DST_BLEND_GL_ZERO,
/* InReverse */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_SRC_ALPHA,
/* Out */
RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | RADEON_DST_BLEND_GL_ZERO,
/* OutReverse */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA,
/* Atop */
RADEON_SRC_BLEND_GL_DST_ALPHA | RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA,
/* AtopReverse */
RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | RADEON_DST_BLEND_GL_SRC_ALPHA,
/* Xor */
RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA | RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA,
/* Add */
RADEON_SRC_BLEND_GL_ONE | RADEON_DST_BLEND_GL_ONE,
/* Saturate */
RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE | RADEON_DST_BLEND_GL_ONE,
/* DisjointClear */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_ZERO,
/* DisjointSrc */
RADEON_SRC_BLEND_GL_ONE | RADEON_DST_BLEND_GL_ZERO,
/* DisjointDst */
RADEON_SRC_BLEND_GL_ZERO | RADEON_DST_BLEND_GL_ONE,
struct blendinfo {
Bool dst_alpha;
Bool src_alpha;
CARD32 blend_cntl;
};
static struct blendinfo RadeonBlendOp[] = {
/* Clear */
{0, 0, RADEON_SBLEND_GL_ZERO | RADEON_DBLEND_GL_ZERO},
/* Src */
{0, 0, RADEON_SBLEND_GL_ONE | RADEON_DBLEND_GL_ZERO},
/* Dst */
{0, 0, RADEON_SBLEND_GL_ZERO | RADEON_DBLEND_GL_ONE},
/* Over */
{0, 1, RADEON_SBLEND_GL_ONE | RADEON_DBLEND_GL_INV_SRC_ALPHA},
/* OverReverse */
{1, 0, RADEON_SBLEND_GL_INV_DST_ALPHA | RADEON_DBLEND_GL_ONE},
/* In */
{1, 0, RADEON_SBLEND_GL_DST_ALPHA | RADEON_DBLEND_GL_ZERO},
/* InReverse */
{0, 1, RADEON_SBLEND_GL_ZERO | RADEON_DBLEND_GL_SRC_ALPHA},
/* Out */
{1, 0, RADEON_SBLEND_GL_INV_DST_ALPHA | RADEON_DBLEND_GL_ZERO},
/* OutReverse */
{0, 1, RADEON_SBLEND_GL_ZERO | RADEON_DBLEND_GL_INV_SRC_ALPHA},
/* Atop */
{1, 1, RADEON_SBLEND_GL_DST_ALPHA | RADEON_DBLEND_GL_INV_SRC_ALPHA},
/* AtopReverse */
{1, 1, RADEON_SBLEND_GL_INV_DST_ALPHA | RADEON_DBLEND_GL_SRC_ALPHA},
/* Xor */
{1, 1, RADEON_SBLEND_GL_INV_DST_ALPHA | RADEON_DBLEND_GL_INV_SRC_ALPHA},
/* Add */
{0, 0, RADEON_SBLEND_GL_ONE | RADEON_DBLEND_GL_ONE},
};
struct formatinfo {
int fmt;
CARD32 card_fmt;
};
/* Note on texture formats:
* TXFORMAT_Y8 expands to (Y,Y,Y,1). TXFORMAT_I8 expands to (I,I,I,I)
*/
static struct formatinfo R100TexFormats[] = {
{PICT_a8r8g8b8, RADEON_TXFORMAT_ARGB8888 | RADEON_TXFORMAT_ALPHA_IN_MAP},
{PICT_x8r8g8b8, RADEON_TXFORMAT_ARGB8888},
{PICT_r5g6b5, RADEON_TXFORMAT_RGB565},
{PICT_a1r5g5b5, RADEON_TXFORMAT_ARGB1555 | RADEON_TXFORMAT_ALPHA_IN_MAP},
{PICT_x1r5g5b5, RADEON_TXFORMAT_ARGB1555},
{PICT_a8, RADEON_TXFORMAT_I8 | RADEON_TXFORMAT_ALPHA_IN_MAP},
};
static struct formatinfo R200TexFormats[] = {
{PICT_a8r8g8b8, R200_TXFORMAT_ARGB8888 | R200_TXFORMAT_ALPHA_IN_MAP},
{PICT_x8r8g8b8, R200_TXFORMAT_ARGB8888},
{PICT_r5g6b5, R200_TXFORMAT_RGB565},
{PICT_a1r5g5b5, R200_TXFORMAT_ARGB1555 | R200_TXFORMAT_ALPHA_IN_MAP},
{PICT_x1r5g5b5, R200_TXFORMAT_ARGB1555},
{PICT_a8, R200_TXFORMAT_I8 | R200_TXFORMAT_ALPHA_IN_MAP},
};
/* Common Radeon setup code */
static Bool
RadeonTextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit)
RadeonGetDestFormat(PicturePtr pDstPicture, CARD32 *dst_format)
{
switch (pDstPicture->format) {
case PICT_a8r8g8b8:
case PICT_x8r8g8b8:
*dst_format = RADEON_COLOR_FORMAT_ARGB8888;
break;
case PICT_r5g6b5:
*dst_format = RADEON_COLOR_FORMAT_RGB565;
break;
case PICT_a1r5g5b5:
case PICT_x1r5g5b5:
*dst_format = RADEON_COLOR_FORMAT_ARGB1555;
break;
case PICT_a8:
*dst_format = RADEON_COLOR_FORMAT_RGB8;
break;
default:
ATI_FALLBACK(("Unsupported dest format 0x%x\n",
pDstPicture->format));
}
return TRUE;
}
/* R100-specific code */
static Bool
R100CheckCompositeTexture(PicturePtr pPict, int unit)
{
ATIScreenInfo *atis = accel_atis;
ATICardInfo *atic = atis->atic;
KdScreenPriv(pPix->drawable.pScreen);
CARD32 txformat, txoffset, txpitch;
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
LOCALS;
int i;
if ((w > 0x7ff) || (h > 0x7ff))
ATI_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h));
switch (pPict->format) {
case PICT_a8r8g8b8:
txformat = RADEON_TXFORMAT_ARGB8888 |
RADEON_TXFORMAT_ALPHA_IN_MAP;
break;
case PICT_x8r8g8b8:
txformat = RADEON_TXFORMAT_ARGB8888;
break;
case PICT_r5g6b5:
txformat = RADEON_TXFORMAT_RGB565;
break;
case PICT_a8:
txformat = RADEON_TXFORMAT_I8 | RADEON_TXFORMAT_ALPHA_IN_MAP;
break;
default:
for (i = 0; i < sizeof(R100TexFormats) / sizeof(R100TexFormats[0]); i++)
{
if (R100TexFormats[i].fmt == pPict->format)
break;
}
if (i == sizeof(R100TexFormats) / sizeof(R100TexFormats[0]))
ATI_FALLBACK(("Unsupported picture format 0x%x\n",
pPict->format));
}
if (pPict->repeat) {
if ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)
ATI_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w,
h));
txformat |= (ATILog2(w) - 1) << RADEON_TXFORMAT_WIDTH_SHIFT;
txformat |= (ATILog2(h) - 1) << RADEON_TXFORMAT_HEIGHT_SHIFT;
if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0))
ATI_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h));
return TRUE;
}
static Bool
R100TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit)
{
ATIScreenInfo *atis = accel_atis;
KdScreenPriv(pPix->drawable.pScreen);
CARD32 txformat, txoffset, txpitch;
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
int i;
RING_LOCALS;
for (i = 0; i < sizeof(R100TexFormats) / sizeof(R100TexFormats[0]); i++)
{
if (R100TexFormats[i].fmt == pPict->format)
break;
}
txformat = R100TexFormats[i].card_fmt;
if (pPict->repeat) {
txformat |= ATILog2(w) << RADEON_TXFORMAT_WIDTH_SHIFT;
txformat |= ATILog2(h) << RADEON_TXFORMAT_HEIGHT_SHIFT;
} else
txformat |= RADEON_TXFORMAT_NON_POWER2;
txformat |= unit << 24; /* RADEON_TXFORMAT_ST_ROUTE_STQX */
txpitch = pPix->devKind;
txoffset = ((CARD8 *)pPix->devPrivate.ptr -
pScreenPriv->screen->memory_base);
if ((txoffset & 0x1f) != 0)
ATI_FALLBACK(("Bad texture offset 0x%x\n", txoffset));
if ((txpitch & 0x1f) != 0)
ATI_FALLBACK(("Bad texture pitch 0x%x\n", txpitch));
/* 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 + 0x18 * unit, 3));
OUT_RING(0);
OUT_RING(txformat);
OUT_RING(txoffset);
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 + 0x8 * unit, 2));
OUT_RING((pPix->drawable.width - 1) |
((pPix->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT));
OUT_RING(txpitch - 32);
END_DMA();
return TRUE;
}
Bool
R100CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture)
{
CARD32 tmp1;
/* Check for unsupported compositing operations. */
if (op >= sizeof(RadeonBlendOp) / sizeof(RadeonBlendOp[0]))
ATI_FALLBACK(("Unsupported Composite op 0x%x\n", op));
if (pSrcPicture->transform)
ATI_FALLBACK(("Source transform unsupported.\n"));
if (pMaskPicture != NULL && pMaskPicture->transform)
ATI_FALLBACK(("Mask transform unsupported.\n"));
if (pMaskPicture != NULL && pMaskPicture->componentAlpha &&
RadeonBlendOp[op].src_alpha)
ATI_FALLBACK(("Component alpha not supported with source "
"alpha blending.\n"));
if (pDstPicture->pDrawable->width >= (1 << 11) ||
pDstPicture->pDrawable->height >= (1 << 11))
ATI_FALLBACK(("Dest w/h too large (%d,%d).\n",
pDstPicture->pDrawable->width,
pDstPicture->pDrawable->height));
if (!R100CheckCompositeTexture(pSrcPicture, 0))
return FALSE;
if (pMaskPicture != NULL && !R100CheckCompositeTexture(pMaskPicture, 1))
return FALSE;
if (!RadeonGetDestFormat(pDstPicture, &tmp1))
return FALSE;
return TRUE;
}
Bool
R100PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
CARD32 dst_format, dst_offset, dst_pitch;
CARD32 pp_cntl, blendcntl, cblend, ablend;
int pixel_shift;
RING_LOCALS;
accel_atis = atis;
RadeonGetDestFormat(pDstPicture, &dst_format);
pixel_shift = pDst->drawable.bitsPerPixel >> 4;
dst_offset = ((CARD8 *)pDst->devPrivate.ptr -
pScreenPriv->screen->memory_base);
dst_pitch = pDst->devKind;
if ((dst_offset & 0x0f) != 0)
ATI_FALLBACK(("Bad destination offset 0x%x\n", dst_offset));
if (((dst_pitch >> pixel_shift) & 0x7) != 0)
ATI_FALLBACK(("Bad destination pitch 0x%x\n", dst_pitch));
if (!R100TextureSetup(pSrcPicture, pSrc, 0))
return FALSE;
pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE;
if (pMask != NULL) {
if (!R100TextureSetup(pMaskPicture, pMask, 1))
return FALSE;
pp_cntl |= RADEON_TEX_1_ENABLE;
}
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(pp_cntl);
OUT_RING(dst_format | RADEON_ALPHA_BLEND_ENABLE);
OUT_RING(dst_offset);
OUT_REG(RADEON_REG_RB3D_COLORPITCH, dst_pitch >> pixel_shift);
/* IN operator: Multiply src by mask components or mask alpha.
* BLEND_CTL_ADD is A * B + C.
* If a picture is a8, we have to explicitly zero its color values.
* If the destination is a8, we have to route the alpha to red, I think.
*/
cblend = RADEON_BLEND_CTL_ADD | RADEON_CLAMP_TX |
RADEON_COLOR_ARG_C_ZERO;
ablend = RADEON_BLEND_CTL_ADD | RADEON_CLAMP_TX |
RADEON_ALPHA_ARG_C_ZERO;
if (pDstPicture->format == PICT_a8)
cblend |= RADEON_COLOR_ARG_A_T0_ALPHA;
else if (pSrcPicture->format == PICT_a8)
cblend |= RADEON_COLOR_ARG_A_ZERO;
else
cblend |= RADEON_COLOR_ARG_A_T0_COLOR;
ablend |= RADEON_ALPHA_ARG_A_T0_ALPHA;
if (pMask) {
if (pMaskPicture->componentAlpha &&
pDstPicture->format != PICT_a8)
cblend |= RADEON_COLOR_ARG_B_T1_COLOR;
else
cblend |= RADEON_COLOR_ARG_B_T1_ALPHA;
ablend |= RADEON_ALPHA_ARG_B_T1_ALPHA;
} else {
cblend |= RADEON_COLOR_ARG_B_ZERO | RADEON_COMP_ARG_B;
ablend |= RADEON_ALPHA_ARG_B_ZERO | RADEON_COMP_ARG_B;
}
OUT_REG(RADEON_REG_PP_TXCBLEND_0, cblend);
OUT_REG(RADEON_REG_PP_TXABLEND_0, ablend);
/* Op operator. */
blendcntl = RadeonBlendOp[op].blend_cntl;
if (PICT_FORMAT_A(pDstPicture->format) == 0 &&
RadeonBlendOp[op].dst_alpha) {
if ((blendcntl & RADEON_SBLEND_MASK) ==
RADEON_SBLEND_GL_DST_ALPHA)
blendcntl = (blendcntl & ~RADEON_SBLEND_MASK) |
RADEON_SBLEND_GL_ONE;
else if ((blendcntl & RADEON_SBLEND_MASK) ==
RADEON_SBLEND_GL_INV_DST_ALPHA)
blendcntl = (blendcntl & ~RADEON_SBLEND_MASK) |
RADEON_SBLEND_GL_ZERO;
}
OUT_REG(RADEON_REG_RB3D_BLENDCNTL, blendcntl);
END_DMA();
return TRUE;
}
static Bool
R200CheckCompositeTexture(PicturePtr pPict, int unit)
{
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
int i;
if ((w > 0x7ff) || (h > 0x7ff))
ATI_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h));
for (i = 0; i < sizeof(R200TexFormats) / sizeof(R200TexFormats[0]); i++)
{
if (R200TexFormats[i].fmt == pPict->format)
break;
}
if (i == sizeof(R200TexFormats) / sizeof(R200TexFormats[0]))
ATI_FALLBACK(("Unsupported picture format 0x%x\n",
pPict->format));
if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0))
ATI_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h));
return TRUE;
}
static Bool
R200TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit)
{
ATIScreenInfo *atis = accel_atis;
KdScreenPriv(pPix->drawable.pScreen);
CARD32 txformat, txoffset, txpitch;
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
int i;
RING_LOCALS;
for (i = 0; i < sizeof(R200TexFormats) / sizeof(R200TexFormats[0]); i++)
{
if (R200TexFormats[i].fmt == pPict->format)
break;
}
txformat = R200TexFormats[i].card_fmt;
if (pPict->repeat) {
txformat |= ATILog2(w) << R200_TXFORMAT_WIDTH_SHIFT;
txformat |= ATILog2(h) << R200_TXFORMAT_HEIGHT_SHIFT;
} else
txformat |= R200_TXFORMAT_NON_POWER2;
txformat |= unit << R200_TXFORMAT_ST_ROUTE_SHIFT;
txpitch = pPix->devKind;
txoffset = ((CARD8 *)pPix->devPrivate.ptr -
pScreenPriv->screen->memory_base);
@ -131,149 +400,154 @@ RadeonTextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit)
if ((txpitch & 0x1f) != 0)
ATI_FALLBACK(("Bad texture pitch 0x%x\n", txpitch));
/* RADEON_REG_PP_TXFILTER_0, RADEON_REG_PP_TXFORMAT_0,
* RADEON_REG_PP_TXOFFSET_0
/* R200_REG_PP_TXFILTER_0,
* R200_REG_PP_TXFORMAT_0,
* R200_REG_PP_TXFORMAT_X_0,
* R200_REG_PP_TXSIZE_0,
* R200_REG_PP_TXPITCH_0
*/
BEGIN_RING(4);
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TXFILTER_0 + 0x18 * unit, 2));
BEGIN_DMA(6);
OUT_RING(DMA_PACKET0(R200_REG_PP_TXFILTER_0 + 0x20 * unit, 5));
OUT_RING(0);
OUT_RING(txformat);
OUT_RING(txoffset);
ADVANCE_RING();
/* RADEON_REG_PP_TEX_SIZE_0, RADEON_REG_PP_TEX_PITCH_0 */
BEGIN_RING(3);
OUT_RING(DMA_PACKET0(RADEON_REG_PP_TEX_SIZE_0 + 0x8 * unit, 1));
OUT_RING(0);
OUT_RING((pPix->drawable.width - 1) |
((pPix->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT));
OUT_RING(txpitch - 32);
ADVANCE_RING();
((pPix->drawable.height - 1) << RADEON_TEX_VSIZE_SHIFT)); /* XXX */
OUT_RING(txpitch - 32); /* XXX */
END_DMA();
BEGIN_DMA(2);
OUT_REG(R200_PP_TXOFFSET_0 + 0x18 * unit, txoffset);
END_DMA();
return TRUE;
}
Bool
RadeonPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
R200CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
CARD32 dst_format, dst_offset, dst_pitch;
CARD32 pp_cntl;
int pixel_shift;
LOCALS;
CARD32 tmp1;
/*ErrorF("RadeonPrepareComposite\n");*/
/* Check for unsupported compositing operations. */
if (op >= sizeof(RadeonBlendOp) / sizeof(RadeonBlendOp[0]))
ATI_FALLBACK(("Unsupported Composite op 0x%x\n", op));
if (pSrcPicture->transform)
ATI_FALLBACK(("Source transform unsupported.\n"));
if (pMaskPicture && pMaskPicture->transform)
if (pMaskPicture != NULL && pMaskPicture->transform)
ATI_FALLBACK(("Mask transform unsupported.\n"));
if (pMaskPicture != NULL && pMaskPicture->componentAlpha &&
RadeonBlendOp[op].src_alpha)
ATI_FALLBACK(("Component alpha not supported with source "
"alpha blending.\n"));
if (!R200CheckCompositeTexture(pSrcPicture, 0))
return FALSE;
if (pMaskPicture != NULL && !R200CheckCompositeTexture(pMaskPicture, 1))
return FALSE;
if (!RadeonGetDestFormat(pDstPicture, &tmp1))
return FALSE;
return TRUE;
}
Bool
R200PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
CARD32 dst_format, dst_offset, dst_pitch;
CARD32 pp_cntl, blendcntl, cblend, ablend;
int pixel_shift;
RING_LOCALS;
RadeonGetDestFormat(pDstPicture, &dst_format);
pixel_shift = pDst->drawable.bitsPerPixel >> 4;
accel_atis = atis;
switch (pDstPicture->format) {
case PICT_r5g6b5:
dst_format = RADEON_COLOR_FORMAT_RGB565;
pixel_shift = 1;
break;
case PICT_a1r5g5b5:
dst_format = RADEON_COLOR_FORMAT_ARGB1555;
pixel_shift = 1;
break;
case PICT_a8r8g8b8:
case PICT_x8r8g8b8:
dst_format = RADEON_COLOR_FORMAT_ARGB8888;
pixel_shift = 2;
break;
default:
ATI_FALLBACK(("Unsupported dest format 0x%x\n",
pDstPicture->format));
}
dst_offset = ((CARD8 *)pDst->devPrivate.ptr -
pScreenPriv->screen->memory_base);
dst_pitch = pDst->devKind;
if ((dst_offset & 0xff) != 0)
if ((dst_offset & 0x0f) != 0)
ATI_FALLBACK(("Bad destination offset 0x%x\n", dst_offset));
if (((dst_pitch >> pixel_shift) & 0x7) != 0)
ATI_FALLBACK(("Bad destination pitch 0x%x\n", dst_pitch));
if (!RadeonTextureSetup(pSrcPicture, pSrc, 0))
if (!R200TextureSetup(pSrcPicture, pSrc, 0))
return FALSE;
pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE;
if (pMask != NULL) {
if (!RadeonTextureSetup(pMaskPicture, pMask, 1))
if (!R200TextureSetup(pMaskPicture, pMask, 1))
return FALSE;
pp_cntl |= RADEON_TEX_1_ENABLE;
}
BEGIN(2);
OUT_REG(RADEON_REG_RE_TOP_LEFT, 0);
OUT_REG(RADEON_REG_RE_WIDTH_HEIGHT, 0xffffffff);
END();
BEGIN_DMA(34);
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN);
BEGIN(11);
OUT_REG(RADEON_REG_PP_CNTL, pp_cntl);
OUT_REG(RADEON_REG_RB3D_CNTL, dst_format | RADEON_ALPHA_BLEND_ENABLE);
/* COLORPITCH is multiples of 8 pixels, but located at the 3rd bit */
OUT_REG(RADEON_REG_RB3D_COLORPITCH, (dst_pitch >> pixel_shift));
OUT_REG(RADEON_REG_RB3D_COLOROFFSET, dst_offset);
OUT_REG(RADEON_REG_RB3D_PLANEMASK, 0xffffffff);
OUT_REG(RADEON_REG_SE_CNTL, RADEON_FFACE_CULL_CCW | RADEON_FFACE_SOLID |
RADEON_VTX_PIX_CENTER_OGL);
OUT_REG(RADEON_REG_SE_CNTL_STATUS, RADEON_TCL_BYPASS);
OUT_REG(RADEON_REG_SE_COORD_FMT,
RADEON_VTX_XY_PRE_MULT_1_OVER_W0 |
RADEON_VTX_ST0_NONPARAMETRIC |
RADEON_VTX_ST1_NONPARAMETRIC |
RADEON_TEX1_W_ROUTING_USE_W0);
if (pMask != NULL) {
/* IN operator: Multiply src by mask components or mask alpha.
* BLEND_CTL_ADD is A * B + C
*/
if (pMaskPicture->componentAlpha)
OUT_REG(RADEON_REG_PP_TXCBLEND_0,
RADEON_COLOR_ARG_A_T0_COLOR |
RADEON_COLOR_ARG_B_T1_COLOR |
RADEON_COLOR_ARG_C_ZERO |
RADEON_BLEND_CTL_ADD |
RADEON_CLAMP_TX);
/* RADEON_REG_PP_CNTL,
* RADEON_REG_RB3D_CNTL,
* RADEON_REG_RB3D_COLOROFFSET
*/
OUT_RING(DMA_PACKET0(RADEON_REG_PP_CNTL, 3));
OUT_RING(pp_cntl);
OUT_RING(dst_format | RADEON_ALPHA_BLEND_ENABLE);
OUT_RING(dst_offset);
OUT_REG(RADEON_REG_RB3D_COLORPITCH, dst_pitch >> pixel_shift);
/* IN operator: Multiply src by mask components or mask alpha.
* BLEND_CTL_ADD is A * B + C.
* If a picture is a8, we have to explicitly zero its color values.
* If the destination is a8, we have to route the alpha to red, I think.
*/
cblend = R200_TXC_OP_MADD | R200_TXC_ARG_C_ZERO;
ablend = R200_TXA_OP_MADD | R200_TXA_ARG_C_ZERO;
if (pDstPicture->format == PICT_a8)
cblend |= R200_TXC_ARG_A_R0_ALPHA;
else if (pSrcPicture->format == PICT_a8)
cblend |= R200_TXC_ARG_A_ZERO;
else
cblend |= R200_TXC_ARG_A_R0_COLOR;
ablend |= R200_TXA_ARG_B_R0_ALPHA;
if (pMask) {
if (pMaskPicture->componentAlpha &&
pDstPicture->format != PICT_a8)
cblend |= R200_TXC_ARG_B_R1_COLOR;
else
OUT_REG(RADEON_REG_PP_TXCBLEND_0,
RADEON_COLOR_ARG_A_T0_COLOR |
RADEON_COLOR_ARG_B_T1_ALPHA |
RADEON_COLOR_ARG_C_ZERO |
RADEON_BLEND_CTL_ADD |
RADEON_CLAMP_TX);
OUT_REG(RADEON_REG_PP_TXABLEND_0,
RADEON_ALPHA_ARG_A_T0_ALPHA |
RADEON_ALPHA_ARG_B_T1_ALPHA |
RADEON_ALPHA_ARG_C_ZERO |
RADEON_BLEND_CTL_ADD);
cblend |= R200_TXC_ARG_B_R1_ALPHA;
ablend |= R200_TXA_ARG_B_R1_ALPHA;
} else {
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);
cblend |= R200_TXC_ARG_B_ZERO | R200_TXC_COMP_ARG_B;
ablend |= R200_TXA_ARG_B_ZERO | R200_TXA_COMP_ARG_B;
}
/* Op operator. */
OUT_REG(RADEON_RB3D_BLENDCNTL, RadeonBlendOp[op]);
END();
RadeonSwitchTo3D();
OUT_REG(R200_REG_PP_TXCBLEND_0, cblend);
OUT_REG(R200_REG_PP_TXABLEND_0, ablend);
OUT_REG(R200_REG_PP_TXCBLEND2_0, 0);
OUT_REG(R200_REG_PP_TXABLEND2_0, 0);
/* Op operator. */
blendcntl = RadeonBlendOp[op].blend_cntl;
if (PICT_FORMAT_A(pDstPicture->format) == 0 &&
RadeonBlendOp[op].dst_alpha) {
blendcntl &= ~RADEON_SBLEND_MASK;
if ((blendcntl & RADEON_SBLEND_MASK) ==
RADEON_SBLEND_GL_DST_ALPHA)
blendcntl |= RADEON_SBLEND_GL_ONE;
else if ((blendcntl & RADEON_SBLEND_MASK) ==
RADEON_SBLEND_GL_INV_DST_ALPHA)
blendcntl |= RADEON_SBLEND_GL_ZERO;
}
OUT_REG(RADEON_REG_RB3D_BLENDCNTL, blendcntl);
END_DMA();
return TRUE;
}
@ -289,7 +563,7 @@ struct blend_vertex {
union intfloat s1, t1;
};
#define VTX_REG_COUNT 6
#define VTX_DWORD_COUNT 6
#define VTX_OUT(vtx) \
do { \
@ -299,8 +573,6 @@ do { \
OUT_RING(vtx.t0.i); \
OUT_RING(vtx.s1.i); \
OUT_RING(vtx.t1.i); \
/*ErrorF("%f,%f %f,%f %f,%f\n", vtx.x.f, vtx.y.f, vtx.s0.f, \
vtx.t0.f, vtx.s1.f, vtx.t1.f);*/ \
} while (0)
void
@ -310,21 +582,10 @@ RadeonComposite(int srcX, int srcY, int maskX, int maskY, int dstX, int dstY,
ATIScreenInfo *atis = accel_atis;
ATICardInfo *atic = atis->atic;
struct blend_vertex vtx[4];
LOCALS;
RING_LOCALS;
/*ErrorF("RadeonComposite %d %d %d %d %d %d\n", srcX, srcY, maskX, maskY,
dstX, dstY, w, h);*/
BEGIN_RING(3 + 4 * VTX_REG_COUNT);
OUT_RING(RADEON_CP_PACKET3_3D_DRAW_IMMD |
((4 * VTX_REG_COUNT + 1) << 16));
OUT_RING(RADEON_CP_VC_FRMT_XY |
RADEON_CP_VC_FRMT_ST0 |
RADEON_CP_VC_FRMT_ST1);
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));
/*ErrorF("RadeonComposite (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n",
srcX, srcY, maskX, maskY,dstX, dstY, w, h);*/
vtx[0].x.f = dstX;
vtx[0].y.f = dstY;
@ -354,36 +615,36 @@ RadeonComposite(int srcX, int srcY, int maskX, int maskY, int dstX, int dstY,
vtx[3].s1.f = maskX + w;
vtx[3].t1.f = maskY;
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 |
RADEON_CP_VC_FRMT_ST1);
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]);
ADVANCE_RING();
END_DMA();
}
void
RadeonDoneComposite(void)
{
/*ErrorF("RadeonDoneComposite\n");*/
}
Bool
RadeonPrepareBlend(int op, PicturePtr pSrcPicture, PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pDst)
{
return RadeonPrepareComposite(op, pSrcPicture, NULL, pDstPicture, pSrc,
NULL, pDst);
}
void
RadeonBlend(int srcX, int srcY, int dstX, int dstY, int width, int height)
{
RadeonComposite(srcX, srcY, 0, 0, dstX, dstY, width, height);
}
void
RadeonDoneBlend(void)
{
RadeonDoneComposite();
}