/* * 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 #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); }