xserver-multidpi/hw/kdrive/ati/ati_draw.c
2007-06-29 14:06:52 -04:00

919 lines
24 KiB
C

/*
* Copyright © 2003 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.
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#include "ati.h"
#include "ati_reg.h"
#include "ati_dma.h"
#include "ati_draw.h"
#include "kaa.h"
CARD8 ATISolidRop[16] = {
/* GXclear */ 0x00, /* 0 */
/* GXand */ 0xa0, /* src AND dst */
/* GXandReverse */ 0x50, /* src AND NOT dst */
/* GXcopy */ 0xf0, /* src */
/* GXandInverted*/ 0x0a, /* NOT src AND dst */
/* GXnoop */ 0xaa, /* dst */
/* GXxor */ 0x5a, /* src XOR dst */
/* GXor */ 0xfa, /* src OR dst */
/* GXnor */ 0x05, /* NOT src AND NOT dst */
/* GXequiv */ 0xa5, /* NOT src XOR dst */
/* GXinvert */ 0x55, /* NOT dst */
/* GXorReverse */ 0xf5, /* src OR NOT dst */
/* GXcopyInverted*/ 0x0f, /* NOT src */
/* GXorInverted */ 0xaf, /* NOT src OR dst */
/* GXnand */ 0x5f, /* NOT src OR NOT dst */
/* GXset */ 0xff, /* 1 */
};
CARD8 ATIBltRop[16] = {
/* GXclear */ 0x00, /* 0 */
/* GXand */ 0x88, /* src AND dst */
/* GXandReverse */ 0x44, /* src AND NOT dst */
/* GXcopy */ 0xcc, /* src */
/* GXandInverted*/ 0x22, /* NOT src AND dst */
/* GXnoop */ 0xaa, /* dst */
/* GXxor */ 0x66, /* src XOR dst */
/* GXor */ 0xee, /* src OR dst */
/* GXnor */ 0x11, /* NOT src AND NOT dst */
/* GXequiv */ 0x99, /* NOT src XOR dst */
/* GXinvert */ 0x55, /* NOT dst */
/* GXorReverse */ 0xdd, /* src OR NOT dst */
/* GXcopyInverted*/ 0x33, /* NOT src */
/* GXorInverted */ 0xbb, /* NOT src OR dst */
/* GXnand */ 0x77, /* NOT src OR NOT dst */
/* GXset */ 0xff, /* 1 */
};
int copydx, copydy;
ATIScreenInfo *accel_atis;
/* If is_24bpp is set, then we are using the accelerator in 8-bit mode due
* to it being broken for 24bpp, so coordinates have to be multiplied by 3.
*/
Bool is_24bpp;
CARD32 settings, color, src_pitch_offset, dst_pitch_offset;
int sample_count;
float sample_offsets_x[255];
float sample_offsets_y[255];
#define DRAW_USING_PACKET3 0
void
ATIDrawSetup(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
RING_LOCALS;
/* XXX: this shouldn't be necessary, but fixes some R128 composite
* issues.
*/
/*if (!atic->is_radeon) {
char *mmio = atic->reg_base;
ATIWaitIdle(atis);
MMIO_OUT32(mmio, R128_REG_PC_GUI_MODE,
R128_PC_BYPASS_EN);
}*/
BEGIN_DMA(2);
OUT_REG(ATI_REG_DEFAULT_SC_BOTTOM_RIGHT,
ATI_DEFAULT_SC_RIGHT_MAX | ATI_DEFAULT_SC_BOTTOM_MAX);
END_DMA();
if (!atic->is_radeon) {
/* Setup for R128 Composite */
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(R128_REG_SETUP_CNTL,
R128_COLOR_SOLID_COLOR |
R128_PRIM_TYPE_TRI |
R128_TEXTURE_ST_MULT_W |
R128_STARTING_VERTEX_1 |
R128_ENDING_VERTEX_3 |
R128_SUB_PIX_4BITS);
OUT_REG(R128_REG_PM4_VC_FPU_SETUP,
R128_FRONT_DIR_CCW |
R128_BACKFACE_CULL |
R128_FRONTFACE_SOLID |
R128_FPU_COLOR_SOLID |
R128_FPU_SUB_PIX_4BITS |
R128_FPU_MODE_3D |
R128_TRAP_BITS_DISABLE |
R128_XFACTOR_2 |
R128_YFACTOR_2 |
R128_FLAT_SHADE_VERTEX_OGL |
R128_FPU_ROUND_TRUNCATE |
R128_WM_SEL_8DW);
OUT_REG(R128_REG_PLANE_3D_MASK_C, 0xffffffff);
OUT_REG(R128_REG_CONSTANT_COLOR_C, 0xff000000);
OUT_REG(R128_REG_WINDOW_XY_OFFSET, 0x00000000);
END_DMA();
} else if (!atic->is_r300) {
/* Setup for R100/R200 Composite */
BEGIN_DMA(8);
OUT_REG(RADEON_REG_RE_TOP_LEFT, 0);
OUT_REG(RADEON_REG_RE_WIDTH_HEIGHT, 0xffffffff);
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);
END_DMA();
if (atic->is_r100) {
BEGIN_DMA(6);
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);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_MODE,
RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH |
RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH);
END_DMA();
} else {
BEGIN_DMA(18);
/* XXX: The 0 below should be RADEON_TCL_BYPASS on
* RS300s.
*/
OUT_REG(R200_REG_SE_VAP_CNTL_STATUS, 0);
OUT_REG(R200_REG_PP_CNTL_X, 0);
OUT_REG(R200_REG_PP_TXMULTI_CTL_0, 0);
OUT_REG(R200_REG_SE_VTX_STATE_CNTL, 0);
OUT_REG(R200_REG_RE_CNTL, 0);
/* XXX: VTX_ST_DENORMALIZED is illegal for the case of
* repeating textures.
*/
OUT_REG(R200_REG_SE_VTE_CNTL, R200_VTX_ST_DENORMALIZED);
OUT_REG(R200_REG_SE_VAP_CNTL,
R200_VAP_FORCE_W_TO_ONE |
R200_VAP_VF_MAX_VTX_NUM);
OUT_REG(R200_REG_RE_AUX_SCISSOR_CNTL, 0);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_MODE,
RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH |
RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH |
R200_RB3D_DC_2D_CACHE_AUTOFREE |
R200_RB3D_DC_3D_CACHE_AUTOFREE);
END_DMA();
}
}
}
static void
ATIWaitMarker(ScreenPtr pScreen, int marker)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ENTER_DRAW(0);
ATIWaitIdle(atis);
LEAVE_DRAW(0);
}
void
RadeonSwitchTo2D(ATIScreenInfo *atis)
{
RING_LOCALS;
ENTER_DRAW(0);
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH);
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
END_DMA();
LEAVE_DRAW(0);
}
void
RadeonSwitchTo3D(ATIScreenInfo *atis)
{
RING_LOCALS;
ENTER_DRAW(0);
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH);
/* We must wait for 3d to idle, in case source was just written as a dest. */
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
END_DMA();
LEAVE_DRAW(0);
}
#if ATI_TRACE_DRAW
void
ATIEnterDraw (PixmapPtr pPix, char *function)
{
if (pPix != NULL) {
KdScreenPriv(pPix->drawable.pScreen);
CARD32 offset;
offset = ((CARD8 *)pPix->devPrivate.ptr -
pScreenPriv->screen->memory_base);
ErrorF ("Enter %s 0x%x (%dx%dx%d/%d)\n", function, offset,
pPix->drawable.width, pPix->drawable.height, pPix->drawable.depth,
pPix->drawable.bitsPerPixel);
} else
ErrorF ("Enter %s\n", function);
}
void
ATILeaveDraw (PixmapPtr pPix, char *function)
{
if (pPix != NULL) {
KdScreenPriv(pPix->drawable.pScreen);
CARD32 offset;
offset = ((CARD8 *)pPix->devPrivate.ptr -
pScreenPriv->screen->memory_base);
ErrorF ("Leave %s 0x%x\n", function, offset);
} else
ErrorF ("Leave %s\n", function);
}
#endif
/* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we
* require src and dest datatypes to be equal.
*/
static Bool
ATIGetDatatypeBpp(int bpp, CARD32 *type)
{
switch (bpp) {
case 8:
*type = R128_DATATYPE_CI8;
return TRUE;
case 16:
*type = R128_DATATYPE_RGB565;
return TRUE;
case 24:
*type = R128_DATATYPE_CI8;
return TRUE;
case 32:
*type = R128_DATATYPE_ARGB8888;
return TRUE;
default:
ATI_FALLBACK(("Unsupported bpp: %d\n", bpp));
return FALSE;
}
}
Bool
ATIGetOffsetPitch(ATIScreenInfo *atis, int bpp, CARD32 *pitch_offset,
int offset, int pitch)
{
ATICardInfo *atic = atis->atic;
/* On the R128, depending on the bpp the screen can be set up so that it
* doesn't meet the pitchAlign requirement but can still be
* accelerated, so we check the specific pitch requirement of alignment
* to 8 pixels.
*/
if (atic->is_radeon) {
if (pitch % atis->kaa.pitchAlign != 0)
ATI_FALLBACK(("Bad pitch 0x%08x\n", pitch));
*pitch_offset = ((pitch >> 6) << 22) | (offset >> 10);
} else {
if (pitch % bpp != 0)
ATI_FALLBACK(("Bad pitch 0x%08x\n", pitch));
*pitch_offset = ((pitch / bpp) << 21) | (offset >> 5);
}
if (offset % atis->kaa.offsetAlign != 0)
ATI_FALLBACK(("Bad offset 0x%08x\n", offset));
return TRUE;
}
Bool
ATIGetPixmapOffsetPitch(PixmapPtr pPix, CARD32 *pitch_offset)
{
KdScreenPriv(pPix->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
CARD32 pitch, offset;
int bpp;
bpp = pPix->drawable.bitsPerPixel;
if (bpp == 24)
bpp = 8;
offset = ((CARD8 *)pPix->devPrivate.ptr -
pScreenPriv->screen->memory_base);
pitch = pPix->devKind;
return ATIGetOffsetPitch(atis, bpp, pitch_offset, offset, pitch);
}
static Bool
ATIPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
{
KdScreenPriv(pPix->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
CARD32 datatype;
RING_LOCALS;
is_24bpp = (pPix->drawable.bitsPerPixel == 24);
accel_atis = atis;
if (is_24bpp) {
/* Solid fills in fake-24bpp mode only work if the pixel color
* and planemask are all the same byte.
*/
if ((fg & 0xffffff) != (((fg & 0xff) << 16) | ((fg >> 8) &
0xffff)))
ATI_FALLBACK(("Can't do solid color 0x%08x in 24bpp\n",
fg));
if ((pm & 0xffffff) != (((pm & 0xff) << 16) | ((pm >> 8) &
0xffff)))
ATI_FALLBACK(("Can't do planemask 0x%08x in 24bpp\n",
pm));
}
if (!ATIGetDatatypeBpp(pPix->drawable.bitsPerPixel, &datatype))
return FALSE;
if (!ATIGetPixmapOffsetPitch(pPix, &dst_pitch_offset))
return FALSE;
ENTER_DRAW(pPix);
if (atic->is_radeon)
RadeonSwitchTo2D(atis);
settings =
ATI_GMC_DST_PITCH_OFFSET_CNTL |
ATI_GMC_BRUSH_SOLID_COLOR |
(datatype << 8) |
ATI_GMC_SRC_DATATYPE_COLOR |
(ATISolidRop[alu] << 16) |
ATI_GMC_CLR_CMP_CNTL_DIS |
R128_GMC_AUX_CLIP_DIS;
color = fg;
#if DRAW_USING_PACKET3
BEGIN_DMA(6);
OUT_REG(ATI_REG_DEFAULT_SC_BOTTOM_RIGHT,
ATI_DEFAULT_SC_RIGHT_MAX | ATI_DEFAULT_SC_BOTTOM_MAX);
OUT_REG(ATI_REG_DP_WRITE_MASK, pm);
OUT_REG(ATI_REG_DP_CNTL, ATI_DST_X_LEFT_TO_RIGHT |
ATI_DST_Y_TOP_TO_BOTTOM);
END_DMA();
#else
BEGIN_DMA(12);
OUT_REG(ATI_REG_DEFAULT_SC_BOTTOM_RIGHT,
ATI_DEFAULT_SC_RIGHT_MAX | ATI_DEFAULT_SC_BOTTOM_MAX);
OUT_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset);
OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL, settings);
OUT_REG(ATI_REG_DP_BRUSH_FRGD_CLR, fg);
OUT_REG(ATI_REG_DP_WRITE_MASK, pm);
OUT_REG(ATI_REG_DP_CNTL, ATI_DST_X_LEFT_TO_RIGHT |
ATI_DST_Y_TOP_TO_BOTTOM);
END_DMA();
#endif
LEAVE_DRAW(pPix);
return TRUE;
}
static void
ATISolid(int x1, int y1, int x2, int y2)
{
ENTER_DRAW(0);
ATIScreenInfo *atis = accel_atis;
RING_LOCALS;
if (is_24bpp) {
x1 *= 3;
x2 *= 3;
}
#if DRAW_USING_PACKET3
BEGIN_DMA(6);
OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_PAINT_MULTI, 5));
OUT_RING(settings);
OUT_RING(dst_pitch_offset);
OUT_RING(color);
OUT_RING((x1 << 16) | y1);
OUT_RING(((x2 - x1) << 16) | (y2 - y1));
END_DMA();
#else
BEGIN_DMA(3);
OUT_RING(DMA_PACKET0(ATI_REG_DST_Y_X, 2));
OUT_RING_REG(ATI_REG_DST_Y_X, (y1 << 16) | x1);
OUT_RING_REG(ATI_REG_DST_HEIGHT_WIDTH, ((y2 - y1) << 16) | (x2 - x1));
END_DMA();
#endif
LEAVE_DRAW(0);
}
static void
ATIDoneSolid(void)
{
ENTER_DRAW(0);
LEAVE_DRAW(0);
}
static Bool
ATIPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, Pixel pm)
{
KdScreenPriv(pDst->drawable.pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
CARD32 datatype;
RING_LOCALS;
copydx = dx;
copydy = dy;
is_24bpp = pDst->drawable.bitsPerPixel == 24;
accel_atis = atis;
if (is_24bpp && ((pm & 0xffffff) != (((pm & 0xff) << 16) | ((pm >> 8) &
0xffff))))
ATI_FALLBACK(("Can't do planemask 0x%08x in 24bpp\n", pm));
if (!ATIGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype))
return FALSE;
if (!ATIGetPixmapOffsetPitch(pSrc, &src_pitch_offset))
return FALSE;
if (!ATIGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
return FALSE;
ENTER_DRAW (pDst);
if (atic->is_radeon)
RadeonSwitchTo2D(atis);
settings =
ATI_GMC_SRC_PITCH_OFFSET_CNTL |
ATI_GMC_DST_PITCH_OFFSET_CNTL |
ATI_GMC_BRUSH_NONE |
(datatype << 8) |
ATI_GMC_SRC_DATATYPE_COLOR |
(ATIBltRop[alu] << 16) |
ATI_DP_SRC_SOURCE_MEMORY |
ATI_GMC_CLR_CMP_CNTL_DIS |
R128_GMC_AUX_CLIP_DIS;
#if DRAW_USING_PACKET3
BEGIN_DMA(6);
OUT_REG(ATI_REG_DEFAULT_SC_BOTTOM_RIGHT,
ATI_DEFAULT_SC_RIGHT_MAX | ATI_DEFAULT_SC_BOTTOM_MAX);
OUT_REG(ATI_REG_DP_WRITE_MASK, pm);
OUT_REG(ATI_REG_DP_CNTL,
(dx >= 0 ? ATI_DST_X_LEFT_TO_RIGHT : 0) |
(dy >= 0 ? ATI_DST_Y_TOP_TO_BOTTOM : 0));
END_DMA();
#else
BEGIN_DMA(12);
OUT_REG(ATI_REG_DEFAULT_SC_BOTTOM_RIGHT,
ATI_DEFAULT_SC_RIGHT_MAX | ATI_DEFAULT_SC_BOTTOM_MAX);
OUT_REG(ATI_REG_SRC_PITCH_OFFSET, src_pitch_offset);
OUT_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset);
OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL, settings);
OUT_REG(ATI_REG_DP_WRITE_MASK, pm);
OUT_REG(ATI_REG_DP_CNTL,
(dx >= 0 ? ATI_DST_X_LEFT_TO_RIGHT : 0) |
(dy >= 0 ? ATI_DST_Y_TOP_TO_BOTTOM : 0));
END_DMA();
#endif
LEAVE_DRAW(pDst);
return TRUE;
}
static void
ATICopy(int srcX, int srcY, int dstX, int dstY, int w, int h)
{
ATIScreenInfo *atis = accel_atis;
RING_LOCALS;
if (is_24bpp) {
srcX *= 3;
dstX *= 3;
w *= 3;
}
#if !DRAW_USING_PACKET3
if (copydx < 0) {
srcX += w - 1;
dstX += w - 1;
}
if (copydy < 0) {
srcY += h - 1;
dstY += h - 1;
}
#endif
#if DRAW_USING_PACKET3
BEGIN_DMA(7);
OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_BITBLT_MULTI, 6));
OUT_RING(settings);
OUT_RING(src_pitch_offset);
OUT_RING(dst_pitch_offset);
OUT_RING((srcX << 16) | srcY);
OUT_RING((dstX << 16) | dstY);
OUT_RING((w << 16) | h);
END_DMA();
#else
BEGIN_DMA(4);
OUT_RING(DMA_PACKET0(ATI_REG_SRC_Y_X, 3));
OUT_RING_REG(ATI_REG_SRC_Y_X, (srcY << 16) | srcX);
OUT_RING_REG(ATI_REG_DST_Y_X, (dstY << 16) | dstX);
OUT_RING_REG(ATI_REG_DST_HEIGHT_WIDTH, (h << 16) | w);
END_DMA();
#endif
}
static void
ATIDoneCopy(void)
{
}
static Bool
ATIUploadToScreen(PixmapPtr pDst, char *src, int src_pitch)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
int width, height, bpp, i, dwords;
int dst_pitch, dst_offset;
CARD32 dst_pitch_offset, datatype;
Bool success;
RING_LOCALS;
ENTER_DRAW (pDst);
LEAVE_DRAW (pDst);
/* XXX: Hostdata uploads aren't working yet. */
return FALSE;
dst_offset = ((CARD8 *)pDst->devPrivate.ptr -
pScreenPriv->screen->memory_base);
dst_pitch = pDst->devKind;
width = pDst->drawable.width;
height = pDst->drawable.height;
bpp = pDst->drawable.bitsPerPixel;
success = ATIGetDatatypeBpp(bpp, &datatype);
if (bpp == 24) {
is_24bpp = TRUE;
bpp = 8;
} else
is_24bpp = FALSE;
if (!ATIGetOffsetPitch(atis, bpp, &dst_pitch_offset, dst_offset,
dst_pitch))
return FALSE;
if (src_pitch != (width * bpp / 8))
return FALSE;
/* No PACKET3 packets when in PIO mode. */
if (atis->using_pio)
return FALSE;
dwords = (width * height * (bpp / 8) + 3) / 4;
/* Flush pixel cache so nothing being written to the destination
* previously gets mixed up with the hostdata blit.
*/
if (atic->is_radeon) {
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_CTLSTAT, RADEON_RB3D_DC_FLUSH);
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_3D_IDLECLEAN |
RADEON_WAIT_HOST_IDLECLEAN);
END_DMA();
} else {
BEGIN_DMA(2);
OUT_REG(R128_REG_PC_GUI_CTLSTAT,
R128_PC_FLUSH_GUI | R128_PC_RI_GUI);
END_DMA();
}
BEGIN_DMA(8);
OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_HOSTDATA_BLT, 7 + dwords));
OUT_RING(ATI_GMC_DST_PITCH_OFFSET_CNTL |
ATI_GMC_BRUSH_NONE |
(datatype << 8) |
ATI_GMC_SRC_DATATYPE_COLOR |
(ATISolidRop[GXcopy] << 16) |
ATI_DP_SRC_SOURCE_HOST_DATA |
ATI_GMC_CLR_CMP_CNTL_DIS |
R128_GMC_AUX_CLIP_DIS |
ATI_GMC_WR_MSK_DIS);
OUT_RING(dst_pitch_offset);
OUT_RING(0xffffffff);
OUT_RING(0xffffffff);
OUT_RING((0 << 16) | 0);
OUT_RING((height << 16) | width);
OUT_RING(dwords);
END_DMA();
for (i = 0; i < dwords; i++) {
BEGIN_DMA(1);
OUT_RING(((CARD32 *)src)[i]);
END_DMA();
}
if (atic->is_radeon) {
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_CTLSTAT,
RADEON_RB3D_DC_FLUSH_ALL);
OUT_REG(ATI_REG_WAIT_UNTIL,
RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_HOST_IDLECLEAN);
END_DMA();
} else {
BEGIN_DMA(2);
OUT_REG(R128_REG_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI);
END_DMA();
}
kaaMarkSync(pScreen);
ErrorF("hostdata upload %d,%d %dbpp\n", width, height, bpp);
return TRUE;
}
static Bool
ATIUploadToScratch(PixmapPtr pSrc, PixmapPtr pDst)
{
KdScreenPriv(pSrc->drawable.pScreen);
ATICardInfo(pScreenPriv);
ATIScreenInfo(pScreenPriv);
int dst_pitch, src_pitch, w, i, size, bytes;
unsigned char *dst, *src;
RING_LOCALS;
ENTER_DRAW(pSrc);
/* Align width to log 2, useful for R128 composite. This should be a
* KAA flag we check for (and supported in kaa.c in general) since many
* older bits of hardware are going to want POT pitches.
*/
w = pSrc->drawable.width;
if (atis->kaa.flags & KAA_OFFSCREEN_ALIGN_POT)
w = 1 << (ATILog2(w - 1) + 1);
dst_pitch = (w * pSrc->drawable.bitsPerPixel / 8 +
atis->kaa.pitchAlign - 1) & ~(atis->kaa.pitchAlign - 1);
size = dst_pitch * pSrc->drawable.height;
if (size > atis->scratch_area->size)
ATI_FALLBACK(("Pixmap too large for scratch (%d,%d)\n",
pSrc->drawable.width, pSrc->drawable.height));
atis->scratch_next = (atis->scratch_next + atis->kaa.offsetAlign - 1) &
~(atis->kaa.offsetAlign - 1);
if (atis->scratch_next + size > atis->scratch_area->offset +
atis->scratch_area->size) {
/* Only sync when we've used all of the scratch area. */
kaaWaitSync(pSrc->drawable.pScreen);
atis->scratch_next = atis->scratch_area->offset;
}
memcpy(pDst, pSrc, sizeof(*pDst));
pDst->devKind = dst_pitch;
pDst->devPrivate.ptr = pScreenPriv->screen->memory_base +
atis->scratch_next;
atis->scratch_next += size;
src = pSrc->devPrivate.ptr;
src_pitch = pSrc->devKind;
dst = pDst->devPrivate.ptr;
bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch;
i = pSrc->drawable.height;
while (i--) {
memcpy(dst, src, bytes);
dst += dst_pitch;
src += src_pitch;
}
/* Flush the pixel cache */
if (atic->is_radeon) {
BEGIN_DMA(4);
OUT_REG(RADEON_REG_RB3D_DSTCACHE_CTLSTAT,
RADEON_RB3D_DC_FLUSH_ALL);
OUT_REG(ATI_REG_WAIT_UNTIL, RADEON_WAIT_HOST_IDLECLEAN);
END_DMA();
} else {
BEGIN_DMA(2);
OUT_REG(R128_REG_PC_GUI_CTLSTAT, R128_PC_FLUSH_ALL);
END_DMA();
}
LEAVE_DRAW(pSrc);
return TRUE;
}
static void
ATIBlockHandler(pointer blockData, OSTimePtr timeout, pointer readmask)
{
ScreenPtr pScreen = (ScreenPtr) blockData;
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
/* When the server is going to sleep, make sure that all DMA data has
* been flushed.
*/
if (atis->indirectBuffer)
ATIFlushIndirect(atis, 1);
}
static void
ATIWakeupHandler(pointer blockData, int result, pointer readmask)
{
}
Bool
ATIDrawInit(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
ErrorF("Screen: %d/%d depth/bpp\n", pScreenPriv->screen->fb[0].depth,
pScreenPriv->screen->fb[0].bitsPerPixel);
RegisterBlockAndWakeupHandlers(ATIBlockHandler, ATIWakeupHandler,
pScreen);
#ifdef USE_DRI
atis->using_dri = ATIDRIScreenInit(pScreen);
#endif /* USE_DRI */
memset(&atis->kaa, 0, sizeof(KaaScreenInfoRec));
atis->kaa.waitMarker = ATIWaitMarker;
atis->kaa.PrepareSolid = ATIPrepareSolid;
atis->kaa.Solid = ATISolid;
atis->kaa.DoneSolid = ATIDoneSolid;
atis->kaa.PrepareCopy = ATIPrepareCopy;
atis->kaa.Copy = ATICopy;
atis->kaa.DoneCopy = ATIDoneCopy;
/* Other acceleration will be hooked in in DrawEnable depending on
* what type of DMA gets initialized.
*/
atis->kaa.flags = KAA_OFFSCREEN_PIXMAPS;
if (atic->is_radeon) {
atis->kaa.offsetAlign = 1024;
atis->kaa.pitchAlign = 64;
} else {
/* Rage 128 compositing wants power-of-two pitches. */
atis->kaa.flags |= KAA_OFFSCREEN_ALIGN_POT;
atis->kaa.offsetAlign = 32;
/* Pitch alignment is in sets of 8 pixels, and we need to cover
* 32bpp, so 32 bytes.
*/
atis->kaa.pitchAlign = 32;
}
kaaInitTrapOffsets(8, sample_offsets_x, sample_offsets_y, 0.0, 0.0);
sample_count = (1 << 8) - 1;
if (!kaaDrawInit(pScreen, &atis->kaa))
return FALSE;
return TRUE;
}
static void
ATIScratchSave(ScreenPtr pScreen, KdOffscreenArea *area)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
atis->scratch_area = NULL;
}
void
ATIDrawEnable(ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
ATICardInfo(pScreenPriv);
ATIDMASetup(pScreen);
ATIDrawSetup(pScreen);
atis->scratch_area = NULL;
atis->kaa.PrepareBlend = NULL;
atis->kaa.Blend = NULL;
atis->kaa.DoneBlend = NULL;
atis->kaa.CheckComposite = NULL;
atis->kaa.PrepareComposite = NULL;
atis->kaa.Composite = NULL;
atis->kaa.DoneComposite = NULL;
atis->kaa.UploadToScreen = NULL;
atis->kaa.UploadToScratch = NULL;
/* We can't dispatch 3d commands in PIO mode. */
if (!atis->using_pio) {
if (!atic->is_radeon) {
atis->kaa.CheckComposite = R128CheckComposite;
atis->kaa.PrepareComposite = R128PrepareComposite;
atis->kaa.Composite = R128Composite;
atis->kaa.DoneComposite = R128DoneComposite;
} else if (atic->is_r100) {
atis->kaa.CheckComposite = R100CheckComposite;
atis->kaa.PrepareComposite = R100PrepareComposite;
atis->kaa.Composite = RadeonComposite;
atis->kaa.DoneComposite = RadeonDoneComposite;
} else if (atic->is_r200) {
atis->kaa.CheckComposite = R200CheckComposite;
atis->kaa.PrepareComposite = R200PrepareComposite;
atis->kaa.Composite = RadeonComposite;
atis->kaa.DoneComposite = RadeonDoneComposite;
}
}
#ifdef USE_DRI
if (atis->using_dri) {
if (!atic->is_radeon) {
/*atis->kaa.PrepareTrapezoids = R128PrepareTrapezoids;
atis->kaa.Trapezoids = R128Trapezoids;
atis->kaa.DoneTrapezoids = R128DoneTrapezoids;*/
} else if (atic->is_r100 || atic->is_r200) {
atis->kaa.PrepareTrapezoids = RadeonPrepareTrapezoids;
atis->kaa.Trapezoids = RadeonTrapezoids;
atis->kaa.DoneTrapezoids = RadeonDoneTrapezoids;
}
}
#endif /* USE_DRI */
atis->kaa.UploadToScreen = ATIUploadToScreen;
/* Reserve a scratch area. It'll be used for storing glyph data during
* Composite operations, because glyphs aren't in real pixmaps and thus
* can't be migrated.
*/
atis->scratch_area = KdOffscreenAlloc(pScreen, 131072,
atis->kaa.offsetAlign, TRUE, ATIScratchSave, atis);
if (atis->scratch_area != NULL) {
atis->scratch_next = atis->scratch_area->offset;
atis->kaa.UploadToScratch = ATIUploadToScratch;
}
kaaMarkSync(pScreen);
}
void
ATIDrawDisable(ScreenPtr pScreen)
{
kaaWaitSync(pScreen);
ATIDMATeardown(pScreen);
}
void
ATIDrawFini(ScreenPtr pScreen)
{
#ifdef USE_DRI
KdScreenPriv(pScreen);
ATIScreenInfo(pScreenPriv);
if (atis->using_dri) {
ATIDRICloseScreen(pScreen);
atis->using_dri = FALSE;
}
#endif /* USE_DRI */
RemoveBlockAndWakeupHandlers(ATIBlockHandler, ATIWakeupHandler,
pScreen);
kaaDrawFini(pScreen);
}