/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DFB_GRAPHICS_DRIVER( mach64 ) #include "regs.h" #include "mmio.h" #include "mach64_state.h" #include "mach64.h" /* driver capability flags */ #define MACH64_SUPPORTED_DRAWINGFLAGS \ (DSDRAW_DST_COLORKEY | DSDRAW_SRC_PREMULTIPLY) #define MACH64_SUPPORTED_BLITTINGFLAGS \ (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY) #define MACH64_SUPPORTED_DRAWINGFUNCTIONS \ (DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE) #define MACH64_SUPPORTED_BLITTINGFUNCTIONS \ (DFXL_BLIT) #define MACH64GT_SUPPORTED_DRAWINGFLAGS \ (DSDRAW_DST_COLORKEY | DSDRAW_BLEND | DSDRAW_SRC_PREMULTIPLY) #define MACH64GT_SUPPORTED_BLITTINGFLAGS \ (DSBLIT_SRC_COLORKEY | DSBLIT_DST_COLORKEY | DSBLIT_BLEND_COLORALPHA | \ DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE | DSBLIT_DEINTERLACE | \ DSBLIT_SRC_PREMULTCOLOR) #define MACH64GT_SUPPORTED_DRAWINGFUNCTIONS \ (DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE | DFXL_FILLTRIANGLE) #define MACH64GT_SUPPORTED_BLITTINGFUNCTIONS \ (DFXL_BLIT | DFXL_STRETCHBLIT) static bool mach64DrawLine2D( void *drv, void *dev, DFBRegion *line ); static bool mach64DrawLine3D( void *drv, void *dev, DFBRegion *line ); static bool mach64Blit2D( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool mach64BlitScaleOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool mach64StretchBlitScaleOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); static bool mach64BlitScale( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool mach64StretchBlitScale( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); static bool mach64BlitTexOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool mach64StretchBlitTexOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); static bool mach64BlitTex( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ); static bool mach64StretchBlitTex( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ); /* required implementations */ static void mach64EngineReset( void *drv, void *dev ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; mach64_waitidle( mdrv, mdev ); mach64_waitfifo( mdrv, mdev, 2 ); mach64_out32( mmio, DP_WRITE_MSK, 0xFFFFFFFF ); mach64_out32( mmio, DP_MIX, FRGD_MIX_SRC | BKGD_MIX_DST ); if (mdrv->accelerator == FB_ACCEL_ATI_MACH64GT) { mach64_waitfifo( mdrv, mdev, 12 ); /* Some 3D registers aren't accessible without this. */ mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); mach64_out32( mmio, SRC_CNTL, 0 ); mach64_out32( mmio, Z_CNTL, 0 ); mach64_out32( mmio, RED_X_INC, 0 ); mach64_out32( mmio, RED_Y_INC, 0 ); mach64_out32( mmio, GREEN_X_INC, 0 ); mach64_out32( mmio, GREEN_Y_INC, 0 ); mach64_out32( mmio, BLUE_X_INC, 0 ); mach64_out32( mmio, BLUE_Y_INC, 0 ); mach64_out32( mmio, ALPHA_X_INC, 0 ); mach64_out32( mmio, ALPHA_Y_INC, 0 ); mach64_out32( mmio, SCALE_3D_CNTL, 0 ); } if (mdev->chip >= CHIP_3D_RAGE_PRO) mach64_out32( mmio, HW_DEBUG, mdev->hw_debug ); } static DFBResult mach64EngineSync( void *drv, void *dev ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64_waitidle( mdrv, mdev ); return DFB_OK; } static void mach64FlushTextureCache( void *drv, void *dev ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; if (mdev->chip >= CHIP_3D_RAGE_PRO) { mach64_waitfifo( mdrv, mdev, 1 ); mach64_out32( mmio, TEX_CNTL, TEX_CACHE_FLUSH ); } } static bool mach64_use_scaler( Mach64DeviceData *mdev, CardState *state, DFBAccelerationMask accel ) { if (accel & DFXL_STRETCHBLIT || state->source->config.format != state->destination->config.format || state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_DEINTERLACE)) return true; return false; } static bool mach64_use_tex( Mach64DeviceData *mdev, CardState *state, DFBAccelerationMask accel ) { if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) return true; /* * 3D Rage II chips lock up if the scaler is used with destination * color keying. Using the texture engine works however. */ if (mdev->chip < CHIP_3D_RAGE_PRO && mach64_use_scaler( mdev, state, accel ) && state->blittingflags & DSBLIT_DST_COLORKEY) return true; return false; } static bool mach64_use_scaler_3d( Mach64DeviceData *mdev, CardState *state, DFBAccelerationMask accel ) { if (DFB_DRAWING_FUNCTION( accel )) { if (state->drawingflags & DSDRAW_BLEND) return true; } else { if (accel & DFXL_STRETCHBLIT || state->source->config.format != state->destination->config.format || state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_DEINTERLACE | DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) return true; } return false; } static bool mach64_check_blend( Mach64DeviceData *mdev, CardState *state ) { switch (state->src_blend) { case DSBF_SRCCOLOR: case DSBF_INVSRCCOLOR: return false; case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: case DSBF_SRCALPHASAT: if (mdev->chip < CHIP_3D_RAGE_PRO) return false; default: break; } switch (state->dst_blend) { case DSBF_DESTCOLOR: case DSBF_INVDESTCOLOR: case DSBF_SRCALPHASAT: return false; case DSBF_DESTALPHA: case DSBF_INVDESTALPHA: if (mdev->chip < CHIP_3D_RAGE_PRO) return false; default: break; } return true; } static void mach64CheckState( void *drv, void *dev, CardState *state, DFBAccelerationMask accel ) { switch (state->destination->config.format) { case DSPF_RGB332: case DSPF_RGB555: case DSPF_ARGB1555: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: break; default: return; } if (DFB_DRAWING_FUNCTION( accel )) { if (state->drawingflags & ~MACH64_SUPPORTED_DRAWINGFLAGS) return; state->accel |= MACH64_SUPPORTED_DRAWINGFUNCTIONS; } else { if (state->source->config.format != state->destination->config.format) return; if (state->blittingflags & ~MACH64_SUPPORTED_BLITTINGFLAGS) return; /* Can't do source and destination color keying at the same time. */ if (state->blittingflags & DSBLIT_SRC_COLORKEY && state->blittingflags & DSBLIT_DST_COLORKEY) return; state->accel |= MACH64_SUPPORTED_BLITTINGFUNCTIONS; } } static void mach64GTCheckState( void *drv, void *dev, CardState *state, DFBAccelerationMask accel ) { Mach64DeviceData *mdev = (Mach64DeviceData*) dev; switch (state->destination->config.format) { case DSPF_RGB444: case DSPF_ARGB4444: /* Not supported. */ if (mdev->chip < CHIP_3D_RAGE_PRO) return; /* Causes the chip to lock up. */ if (mdev->chip < CHIP_3D_RAGE_XLXC && mach64_use_scaler_3d( mdev, state, accel )) return; case DSPF_RGB332: case DSPF_RGB555: case DSPF_ARGB1555: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: break; default: return; } if (DFB_DRAWING_FUNCTION( accel )) { if (state->drawingflags & ~MACH64GT_SUPPORTED_DRAWINGFLAGS) return; if (state->drawingflags & DSDRAW_BLEND && !mach64_check_blend( mdev, state )) return; /* Causes the chip to lock up. */ if (state->drawingflags & DSDRAW_BLEND && state->drawingflags & DSDRAW_DST_COLORKEY) return; state->accel |= MACH64GT_SUPPORTED_DRAWINGFUNCTIONS; } else { CoreSurface *source = state->source; switch (source->config.format) { case DSPF_RGB332: case DSPF_RGB555: case DSPF_ARGB1555: case DSPF_RGB444: case DSPF_ARGB4444: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: break; default: return; } if (state->blittingflags & ~MACH64GT_SUPPORTED_BLITTINGFLAGS) return; if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA) && !mach64_check_blend( mdev, state )) return; /* Can't do alpha modulation. */ if (state->blittingflags & DSBLIT_BLEND_ALPHACHANNEL && state->blittingflags & DSBLIT_BLEND_COLORALPHA) return; /* Can't do source and destination color keying at the same time. */ if (state->blittingflags & DSBLIT_SRC_COLORKEY && state->blittingflags & DSBLIT_DST_COLORKEY) return; /* Causes the chip to lock up. */ if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA) && state->blittingflags & DSBLIT_DST_COLORKEY) return; if (mach64_use_tex( mdev, state, accel )) { /* Max texture size is 1024x1024. */ if (source->config.size.w > 1024 || source->config.size.h > 1024) return; state->accel |= MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; } else if (mach64_use_scaler( mdev, state, accel )) { /* Max scaler source size depends on the chip type. */ if (mdev->chip < CHIP_3D_RAGE_PRO) { /* Tested on 3D Rage II+ and IIC. */ if (source->config.size.w > 4095 || source->config.size.h > 4095) return; } else { /* Tested on 3D Rage LT Pro, XL and Mobility. */ if (source->config.size.w > 4096 || source->config.size.h > 16384) return; } state->accel |= MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; } else state->accel |= accel; } } static void mach64SetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; if (state->mod_hw == SMF_ALL) { mdev->valid = 0; } else if (state->mod_hw) { if (state->mod_hw & SMF_SOURCE) MACH64_INVALIDATE( m_source | m_srckey ); if (state->mod_hw & SMF_SRC_COLORKEY) MACH64_INVALIDATE( m_srckey ); if (state->mod_hw & SMF_DESTINATION) MACH64_INVALIDATE( m_color | m_dstkey ); if (state->mod_hw & SMF_COLOR) MACH64_INVALIDATE( m_color ); if (state->mod_hw & SMF_DST_COLORKEY) MACH64_INVALIDATE( m_dstkey ); if (state->mod_hw & SMF_BLITTING_FLAGS) MACH64_INVALIDATE( m_srckey | m_dstkey | m_disable_key ); if (state->mod_hw & SMF_DRAWING_FLAGS) MACH64_INVALIDATE( m_color | m_dstkey | m_disable_key ); } if (state->mod_hw & SMF_DESTINATION) mach64_set_destination( mdrv, mdev, state ); switch (accel) { case DFXL_FILLRECTANGLE: case DFXL_DRAWRECTANGLE: case DFXL_DRAWLINE: mach64_waitfifo( mdrv, mdev, 2 ); mach64_out32( mmio, DP_SRC, FRGD_SRC_FRGD_CLR ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); mach64_set_color( mdrv, mdev, state ); if (state->drawingflags & DSDRAW_DST_COLORKEY) mach64_set_dst_colorkey( mdrv, mdev, state ); else mach64_disable_colorkey( mdrv, mdev ); funcs->DrawLine = mach64DrawLine2D; state->set = DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE; break; case DFXL_BLIT: mach64_set_source( mdrv, mdev, state ); mach64_waitfifo( mdrv, mdev, 2 ); mach64_out32( mmio, DP_SRC, FRGD_SRC_BLIT ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); if (state->blittingflags & DSBLIT_DST_COLORKEY) mach64_set_dst_colorkey( mdrv, mdev, state ); else if (state->blittingflags & DSBLIT_SRC_COLORKEY) mach64_set_src_colorkey( mdrv, mdev, state ); else mach64_disable_colorkey( mdrv, mdev ); funcs->Blit = mach64Blit2D; state->set = DFXL_BLIT; break; default: D_BUG( "unexpected drawing/blitting function" ); break; } if (state->mod_hw & SMF_CLIP) { mach64_set_clip( mdrv, mdev, state ); mdev->clip = state->clip; } state->mod_hw = 0; } static void mach64GTSetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; bool use_scaler_3d; if (state->mod_hw == SMF_ALL) { mdev->valid = 0; } else if (state->mod_hw) { if (state->mod_hw & SMF_SOURCE) MACH64_INVALIDATE( m_source | m_source_scale | m_srckey | m_srckey_scale | m_blit_blend ); if (state->mod_hw & SMF_SRC_COLORKEY) MACH64_INVALIDATE( m_srckey | m_srckey_scale ); if (state->mod_hw & SMF_DESTINATION) MACH64_INVALIDATE( m_color | m_dstkey ); if (state->mod_hw & SMF_COLOR) MACH64_INVALIDATE( m_color | m_color_3d | m_color_tex ); if (state->mod_hw & SMF_DST_COLORKEY) MACH64_INVALIDATE( m_dstkey ); if (state->mod_hw & SMF_BLITTING_FLAGS) MACH64_INVALIDATE( m_color_tex | m_source_scale | m_srckey | m_srckey_scale | m_dstkey | m_disable_key | m_blit_blend ); if (state->mod_hw & SMF_DRAWING_FLAGS) MACH64_INVALIDATE( m_color | m_color_3d | m_dstkey | m_disable_key | m_draw_blend ); if (state->mod_hw & (SMF_SRC_BLEND | SMF_DST_BLEND)) MACH64_INVALIDATE( m_draw_blend | m_blit_blend ); } use_scaler_3d = mach64_use_scaler_3d( mdev, state, accel ); /* At least 3D Rage II+ and IIC chips _will_ lock up without this. */ if (mdev->chip < CHIP_3D_RAGE_PRO && use_scaler_3d != mdev->use_scaler_3d) mach64_waitidle( mdrv, mdev ); mdev->use_scaler_3d = use_scaler_3d; if (state->mod_hw & SMF_DESTINATION) mach64gt_set_destination( mdrv, mdev, state ); switch (accel) { case DFXL_FILLRECTANGLE: case DFXL_DRAWRECTANGLE: case DFXL_DRAWLINE: case DFXL_FILLTRIANGLE: if (use_scaler_3d) { mach64_waitfifo( mdrv, mdev, 3 ); /* Some 3D registers aren't accessible without this. */ mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); mach64_out32( mmio, DP_SRC, FRGD_SRC_SCALE ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); mach64_set_color_3d( mdrv, mdev, state ); mach64_set_draw_blend( mdrv, mdev, state ); mach64_waitfifo( mdrv, mdev, 1 ); mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE | mdev->draw_blend ); funcs->DrawLine = mach64DrawLine3D; } else { mach64_waitfifo( mdrv, mdev, 3 ); mach64_out32( mmio, SCALE_3D_CNTL, 0 ); mach64_out32( mmio, DP_SRC, FRGD_SRC_FRGD_CLR ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); mach64_set_color( mdrv, mdev, state ); funcs->DrawLine = mach64DrawLine2D; } if (state->drawingflags & DSDRAW_DST_COLORKEY) mach64_set_dst_colorkey( mdrv, mdev, state ); else mach64_disable_colorkey( mdrv, mdev ); state->set = DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE | DFXL_FILLTRIANGLE; break; case DFXL_BLIT: case DFXL_STRETCHBLIT: mdev->blit_deinterlace = state->blittingflags & DSBLIT_DEINTERLACE; if (use_scaler_3d) { mach64_waitfifo( mdrv, mdev, 1 ); /* Some 3D registers aren't accessible without this. */ mach64_out32( mmio, SCALE_3D_CNTL, SCALE_3D_FCN_SHADE ); mach64gt_set_source_scale( mdrv, mdev, state ); mach64_waitfifo( mdrv, mdev, 2 ); mach64_out32( mmio, DP_SRC, FRGD_SRC_SCALE ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); if (state->blittingflags & (DSBLIT_BLEND_COLORALPHA | DSBLIT_COLORIZE | DSBLIT_SRC_PREMULTCOLOR)) mach64_set_color_tex( mdrv, mdev, state ); mach64_set_blit_blend( mdrv, mdev, state ); if (state->blittingflags & DSBLIT_DST_COLORKEY) mach64_set_dst_colorkey( mdrv, mdev, state ); else if (state->blittingflags & DSBLIT_SRC_COLORKEY) mach64_set_src_colorkey_scale( mdrv, mdev, state ); else mach64_disable_colorkey( mdrv, mdev ); if (mdev->chip < CHIP_3D_RAGE_PRO) { if (mach64_use_tex( mdev, state, accel )) { funcs->Blit = mach64BlitTexOld; funcs->StretchBlit = mach64StretchBlitTexOld; } else { funcs->Blit = mach64BlitScaleOld; funcs->StretchBlit = mach64StretchBlitScaleOld; } } else { if (mach64_use_tex( mdev, state, accel )) { funcs->Blit = mach64BlitTex; funcs->StretchBlit = mach64StretchBlitTex; } else { funcs->Blit = mach64BlitScale; funcs->StretchBlit = mach64StretchBlitScale; } } state->set = DFXL_BLIT | DFXL_STRETCHBLIT; } else { mach64_waitfifo( mdrv, mdev, 1 ); mach64_out32( mmio, SCALE_3D_CNTL, 0 ); mach64gt_set_source( mdrv, mdev, state ); mach64_waitfifo( mdrv, mdev, 2 ); mach64_out32( mmio, DP_SRC, FRGD_SRC_BLIT ); mach64_out32( mmio, DP_PIX_WIDTH, mdev->pix_width ); if (state->blittingflags & DSBLIT_DST_COLORKEY) mach64_set_dst_colorkey( mdrv, mdev, state ); else if (state->blittingflags & DSBLIT_SRC_COLORKEY) mach64_set_src_colorkey( mdrv, mdev, state ); else mach64_disable_colorkey( mdrv, mdev ); funcs->Blit = mach64Blit2D; state->set = DFXL_BLIT; } break; default: D_BUG( "unexpected drawing/blitting function" ); break; } if (state->mod_hw & SMF_CLIP) { mach64_set_clip( mdrv, mdev, state ); mdev->clip = state->clip; } state->mod_hw = 0; } /* */ static bool mach64FillRectangle( void *drv, void *dev, DFBRectangle *rect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; mach64_waitfifo( mdrv, mdev, 3 ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( rect->x ) << 16) | S14( rect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | rect->h ); return true; } static bool mach64DrawRectangle( void *drv, void *dev, DFBRectangle *rect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; volatile u8 *mmio = mdrv->mmio_base; int x2 = rect->x + rect->w - 1; int y2 = rect->y + rect->h - 1; mach64_waitfifo( mdrv, mdev, 8 ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( rect->x ) << 16) | S14( rect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (1 << 16) | rect->h ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | 1 ); mach64_out32( mmio, DST_CNTL, 0 ); mach64_out32( mmio, DST_Y_X, (S13( x2 ) << 16) | S14( y2 ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (1 << 16) | rect->h ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (rect->w << 16) | 1 ); return true; } static void mach64_draw_line( Mach64DriverData *mdrv, Mach64DeviceData *mdev, int x1, int y1, int x2, int y2, bool draw_3d ) { volatile u8 *mmio = mdrv->mmio_base; u32 dst_cntl = 0; int dx, dy; dx = x2 - x1; dy = y2 - y1; if (dx < 0) dx = -dx; else dst_cntl |= DST_X_DIR; if (dy < 0) dy = -dy; else dst_cntl |= DST_Y_DIR; if (!dx || !dy) { /* horizontal / vertical line */ mach64_waitfifo( mdrv, mdev, 3 ); mach64_out32( mmio, DST_CNTL, dst_cntl); mach64_out32( mmio, DST_Y_X, (S13( x1 ) << 16) | S14( y1 ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, ((dx+1) << 16) | (dy+1) ); return; } if (dx < dy) { int tmp = dx; dx = dy; dy = tmp; dst_cntl |= DST_Y_MAJOR; } mach64_waitfifo( mdrv, mdev, 6 ); mach64_out32( mmio, DST_CNTL, DST_LAST_PEL | dst_cntl ); mach64_out32( mmio, DST_Y_X, (S13( x1 ) << 16) | S14( y1 ) ); /* Bresenham parameters must be calculated differently * for the 2D and 3D engines. */ if (draw_3d) { mach64_out32( mmio, DST_BRES_ERR, -dx ); mach64_out32( mmio, DST_BRES_INC, 2*dy ); mach64_out32( mmio, DST_BRES_DEC, -2*dx ); mach64_out32( mmio, DST_BRES_LNTH, dx+1 ); } else { mach64_out32( mmio, DST_BRES_ERR, 2*dy-dx ); mach64_out32( mmio, DST_BRES_INC, 2*dy ); mach64_out32( mmio, DST_BRES_DEC, 2*dy-2*dx ); mach64_out32( mmio, DST_BRES_LNTH, dx+1 ); } } static bool mach64DrawLine2D( void *drv, void *dev, DFBRegion *line ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64_draw_line( mdrv, mdev, line->x1, line->y1, line->x2, line->y2, false ); return true; } static bool mach64DrawLine3D( void *drv, void *dev, DFBRegion *line ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64_draw_line( mdrv, mdev, line->x1, line->y1, line->x2, line->y2, true ); return true; } static void mach64_fill_trapezoid( Mach64DriverData *mdrv, Mach64DeviceData *mdev, int X1l, int X1r, int X2l, int X2r, int Y, int dY ) { volatile u8 *mmio = mdrv->mmio_base; u32 dst_cntl; int dXl, dXr; X1r++; X2r++; dst_cntl = DST_Y_DIR | TRAP_FILL_DIR; dXl = X2l - X1l; if (dXl < 0) dXl = -dXl; else dst_cntl |= DST_X_DIR; dXr = X2r - X1r; if (dXr < 0) dXr = -dXr; else dst_cntl |= TRAIL_X_DIR; mach64_waitfifo( mdrv, mdev, 9 ); mach64_out32( mmio, DST_CNTL, dst_cntl ); mach64_out32( mmio, DST_Y_X, (S13( X1l ) << 16) | S14( Y ) ); mach64_out32( mmio, LEAD_BRES_ERR, -dY ); mach64_out32( mmio, LEAD_BRES_INC, 2*dXl ); mach64_out32( mmio, LEAD_BRES_DEC, -2*dY ); mach64_out32( mmio, TRAIL_BRES_ERR, -dY ); mach64_out32( mmio, TRAIL_BRES_INC, 2*dXr ); mach64_out32( mmio, TRAIL_BRES_DEC, -2*dY ); mach64_out32( mmio, LEAD_BRES_LNTH, (S14( X1r ) << 16) | (dY+1) | DRAW_TRAP | LINE_DIS ); } static bool mach64FillTriangle( void *drv, void *dev, DFBTriangle *tri ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; dfb_sort_triangle( tri ); if (tri->y2 == tri->y3) { mach64_fill_trapezoid( mdrv, mdev, tri->x1, tri->x1, MIN( tri->x2, tri->x3), MAX( tri->x2, tri->x3 ), tri->y1, tri->y3 - tri->y1 ); } else if (tri->y1 == tri->y2) { mach64_fill_trapezoid( mdrv, mdev, MIN( tri->x1, tri->x2), MAX( tri->x1, tri->x2 ), tri->x3, tri->x3, tri->y1, tri->y3 - tri->y1 ); } else { int majDx = tri->x3 - tri->x1; int majDy = tri->y3 - tri->y1; int topDx = tri->x2 - tri->x1; int topDy = tri->y2 - tri->y1; int botDy = tri->y3 - tri->y2; int topXperY = (topDx << 20) / topDy; int X2a = tri->x1 + (((topXperY * topDy) + (1<<19)) >> 20); int majXperY = (majDx << 20) / majDy; int majX2 = tri->x1 + (((majXperY * topDy) + (1<<19)) >> 20); int majX2a = majX2 - ((majXperY + (1<<19)) >> 20); mach64_fill_trapezoid( mdrv, mdev, tri->x1, tri->x1, MIN( X2a, majX2a ), MAX( X2a, majX2a ), tri->y1, topDy - 1 ); mach64_fill_trapezoid( mdrv, mdev, MIN( tri->x2, majX2 ), MAX( tri->x2, majX2 ), tri->x3, tri->x3, tri->y2, botDy ); } return true; } static void mach64DoBlit2D( Mach64DriverData *mdrv, Mach64DeviceData *mdev, DFBRectangle *srect, DFBRectangle *drect ) { volatile u8 *mmio = mdrv->mmio_base; u32 dst_cntl = 0; if (srect->x <= drect->x) { srect->x += srect->w - 1; drect->x += drect->w - 1; } else dst_cntl |= DST_X_DIR; if (srect->y <= drect->y) { srect->y += srect->h - 1; drect->y += drect->h - 1; } else dst_cntl |= DST_Y_DIR; mach64_waitfifo( mdrv, mdev, 5 ); mach64_out32( mmio, SRC_Y_X, (S13( srect->x ) << 16) | S14( srect->y ) ); mach64_out32( mmio, SRC_HEIGHT1_WIDTH1, (srect->w << 16) | srect->h ); mach64_out32( mmio, DST_CNTL, dst_cntl ); mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); } static void mach64DoBlitScaleOld( Mach64DriverData *mdrv, Mach64DeviceData *mdev, DFBRectangle *srect, DFBRectangle *drect, bool filter ) { volatile u8 *mmio = mdrv->mmio_base; CoreSurface *source = mdev->source; u32 scale_3d_cntl = SCALE_3D_FCN_SCALE | mdev->blit_blend; int hacc, vacc; if (!filter) scale_3d_cntl |= SCALE_PIX_REP; if (mdev->blit_deinterlace) { srect->y /= 2; srect->h /= 2; } srect->x <<= 16; srect->y <<= 16; srect->w <<= 16; srect->h <<= 16; /* * SCALE_HACC and SCALE_VACC have limited scale so we need to change * SCALE_Y_OFF in order to handle the full range of source coordinates. */ hacc = srect->x & 0xFFFF0; /* s4.12 */ vacc = srect->y & 0xFFFF0; /* s4.12 */ srect->x &= ~0xFFFFF; srect->y &= ~0xFFFFF; mach64_waitfifo( mdrv, mdev, 14 ); mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); mach64_out32( mmio, SCALE_Y_OFF, mdev->scale_offset + (srect->y >> 16) * mdev->scale_pitch + (srect->x >> 16) * DFB_BYTES_PER_PIXEL( source->config.format ) ); mach64_out32( mmio, SCALE_WIDTH, (srect->w + hacc) >> 16 ); mach64_out32( mmio, SCALE_HEIGHT, (srect->h + vacc) >> 16 ); mach64_out32( mmio, SCALE_Y_PITCH, mdev->scale_pitch / DFB_BYTES_PER_PIXEL( source->config.format ) ); mach64_out32( mmio, SCALE_X_INC, srect->w / drect->w ); mach64_out32( mmio, SCALE_Y_INC, srect->h / drect->h ); if (mdev->blit_deinterlace && mdev->field) vacc += 0x8000; mach64_out32( mmio, SCALE_VACC, vacc ); mach64_out32( mmio, SCALE_HACC, hacc ); mach64_out32( mmio, SCALE_XUV_INC, (srect->w/2) / (drect->w/2) ); mach64_out32( mmio, SCALE_UV_HACC, hacc >> 1 ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); /* Some scaler and 3D color registers are shared. */ MACH64_INVALIDATE( m_color_3d | m_color_tex ); } static void mach64DoBlitScale( Mach64DriverData *mdrv, Mach64DeviceData *mdev, DFBRectangle *srect, DFBRectangle *drect, bool filter ) { volatile u8 *mmio = mdrv->mmio_base; CoreSurface *source = mdev->source; u32 scale_3d_cntl = SCALE_3D_FCN_SCALE | mdev->blit_blend; int hacc, vacc; if (!filter) scale_3d_cntl |= SCALE_PIX_REP; if (mdev->blit_deinterlace) { srect->y /= 2; srect->h /= 2; } srect->x <<= 16; srect->y <<= 16; srect->w <<= 16; srect->h <<= 16; /* Hardware bug: Hitting SC_TOP results in incorrect rendering. */ if (drect->y < mdev->clip.y1) { int sy, dy; dy = mdev->clip.y1 - drect->y; sy = (u64) srect->h * dy / drect->h; srect->y += sy; srect->h -= sy; drect->y += dy; drect->h -= dy; } /* * SCALE_HACC and SCALE_VACC have limited scale so we need to change * SCALE_OFF in order to handle the full range of source coordinates. */ hacc = srect->x & 0xFFFFF0; /* s8.12 */ vacc = srect->y & 0xFFFF0; /* s4.12 */ srect->x &= ~0xFFFFFF; srect->y &= ~0xFFFFF; mach64_waitfifo( mdrv, mdev, 12 ); mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); mach64_out32( mmio, SCALE_OFF, mdev->scale_offset + (srect->y >> 16) * mdev->scale_pitch + (srect->x >> 16) * DFB_BYTES_PER_PIXEL( source->config.format ) ); mach64_out32( mmio, SCALE_WIDTH, (srect->w + hacc) >> 16 ); mach64_out32( mmio, SCALE_HEIGHT, (srect->h + vacc) >> 16 ); mach64_out32( mmio, SCALE_PITCH, mdev->scale_pitch / DFB_BYTES_PER_PIXEL( source->config.format ) ); mach64_out32( mmio, SCALE_X_INC, srect->w / drect->w ); mach64_out32( mmio, SCALE_Y_INC, srect->h / drect->h ); if (mdev->blit_deinterlace && mdev->field) vacc += 0x8000; mach64_out32( mmio, SCALE_VACC, vacc ); mach64_out32( mmio, SCALE_HACC, hacc ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); /* Some scaler and 3D color registers are shared. */ MACH64_INVALIDATE( m_color_3d | m_color_tex ); } static void mach64DoBlitTexOld( Mach64DriverData *mdrv, Mach64DeviceData *mdev, DFBRectangle *srect, DFBRectangle *drect, bool filter ) { volatile u8 *mmio = mdrv->mmio_base; u32 scale_3d_cntl = SCALE_3D_FCN_TEXTURE | MIP_MAP_DISABLE | mdev->blit_blend; if (mdev->blit_deinterlace) { srect->y /= 2; srect->h /= 2; } srect->x <<= 1; srect->y <<= 1; srect->w <<= 1; srect->h <<= 1; /* Must add 0.5 to get correct rendering. */ srect->x += 0x1; srect->y += 0x1; if (filter) { /* Avoid using texels outside of texture. */ srect->w -= 0x2; srect->h -= 0x2; scale_3d_cntl |= BILINEAR_TEX_EN | TEX_BLEND_FCN_LINEAR_MIPMAP_NEAREST; } if (mdev->blit_deinterlace && mdev->field) srect->y += 0x1; mach64_waitfifo( mdrv, mdev, 14 ); mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); mach64_out32( mmio, TEX_0_OFF + (mdev->tex_size << 2), mdev->tex_offset ); mach64_out32( mmio, S_X_INC2, 0 ); mach64_out32( mmio, S_Y_INC2, 0 ); mach64_out32( mmio, S_XY_INC2, 0 ); mach64_out32( mmio, S_X_INC_START, (srect->w << (25 - mdev->tex_size)) / drect->w ); mach64_out32( mmio, S_Y_INC, 0 ); mach64_out32( mmio, S_START, (srect->x << (25 - mdev->tex_size)) ); mach64_out32( mmio, T_X_INC2, 0 ); mach64_out32( mmio, T_Y_INC2, 0 ); mach64_out32( mmio, T_XY_INC2, 0 ); mach64_out32( mmio, T_X_INC_START, 0 ); mach64_out32( mmio, T_Y_INC, (srect->h << (25 - mdev->tex_size)) / drect->h ); mach64_out32( mmio, T_START, (srect->y << (25 - mdev->tex_size)) ); mach64_waitfifo( mdrv, mdev, 3 ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); } static void mach64DoBlitTex( Mach64DriverData *mdrv, Mach64DeviceData *mdev, DFBRectangle *srect, DFBRectangle *drect, bool filter ) { volatile u8 *mmio = mdrv->mmio_base; u32 scale_3d_cntl = SCALE_3D_FCN_TEXTURE | MIP_MAP_DISABLE | mdev->blit_blend; if (mdev->blit_deinterlace) { srect->y /= 2; srect->h /= 2; } srect->x <<= 1; srect->y <<= 1; srect->w <<= 1; srect->h <<= 1; /* Must add 0.5 to get correct rendering. */ srect->x += 0x1; srect->y += 0x1; if (filter) { /* Avoid using texels outside of texture. */ srect->w -= 0x2; srect->h -= 0x2; scale_3d_cntl |= BILINEAR_TEX_EN | TEX_BLEND_FCN_LINEAR_MIPMAP_NEAREST; } if (mdev->blit_deinterlace && mdev->field) srect->y += 0x1; mach64_waitfifo( mdrv, mdev, 13 ); mach64_out32( mmio, SCALE_3D_CNTL, scale_3d_cntl ); mach64_out32( mmio, TEX_0_OFF + (mdev->tex_size << 2), mdev->tex_offset ); mach64_out32( mmio, STW_EXP, (1 << 16) | (0 << 8) | (0 << 0) ); /* This register doesn't seem to have any effect on the result. */ mach64_out32( mmio, LOG_MAX_INC, 0 ); mach64_out32( mmio, S_X_INC, (srect->w << (23 - mdev->tex_pitch)) / drect->w ); mach64_out32( mmio, S_Y_INC, 0 ); mach64_out32( mmio, S_START, (srect->x << (23 - mdev->tex_pitch)) ); mach64_out32( mmio, W_X_INC, 0 ); mach64_out32( mmio, W_Y_INC, 0 ); mach64_out32( mmio, W_START, 1 << 23 ); mach64_out32( mmio, T_X_INC, 0 ); mach64_out32( mmio, T_Y_INC, (srect->h << (23 - mdev->tex_height)) / drect->h ); mach64_out32( mmio, T_START, (srect->y << (23 - mdev->tex_height)) ); mach64_waitfifo( mdrv, mdev, 3 ); mach64_out32( mmio, DST_CNTL, DST_X_DIR | DST_Y_DIR ); mach64_out32( mmio, DST_Y_X, (S13( drect->x ) << 16) | S14( drect->y ) ); mach64_out32( mmio, DST_HEIGHT_WIDTH, (drect->w << 16) | drect->h ); } static bool mach64Blit2D( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; DFBRectangle drect = { dx, dy, rect->w, rect->h }; mach64DoBlit2D( mdrv, mdev, rect, &drect ); return true; } static bool mach64BlitScaleOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; DFBRectangle drect = { dx, dy, rect->w, rect->h }; mach64DoBlitScaleOld( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); return true; } static bool mach64StretchBlitScaleOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64DoBlitScaleOld( mdrv, mdev, srect, drect, true ); return true; } static bool mach64BlitScale( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; DFBRectangle drect = { dx, dy, rect->w, rect->h }; mach64DoBlitScale( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); return true; } static bool mach64StretchBlitScale( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64DoBlitScale( mdrv, mdev, srect, drect, true ); return true; } static bool mach64BlitTexOld( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; DFBRectangle drect = { dx, dy, rect->w, rect->h }; mach64DoBlitTexOld( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); return true; } static bool mach64StretchBlitTexOld( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64DoBlitTexOld( mdrv, mdev, srect, drect, true ); return true; } static bool mach64BlitTex( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; DFBRectangle drect = { dx, dy, rect->w, rect->h }; mach64DoBlitTex( mdrv, mdev, rect, &drect, mdev->blit_deinterlace ); return true; } static bool mach64StretchBlitTex( void *drv, void *dev, DFBRectangle *srect, DFBRectangle *drect ) { Mach64DriverData *mdrv = (Mach64DriverData*) drv; Mach64DeviceData *mdev = (Mach64DeviceData*) dev; mach64DoBlitTex( mdrv, mdev, srect, drect, true ); return true; } /* */ #define MACH64_CFG_CHIP_TYPE( a, b ) (((a) << 8) | (b)) static Mach64ChipType mach64_chip_type_vt( Mach64DriverData *mdrv, GraphicsDeviceInfo *device_info ) { u32 config_chip_id = mach64_in32( mdrv->mmio_base, CONFIG_CHIP_ID ); u32 cfg_chip_type = config_chip_id & CFG_CHIP_TYPE; switch (cfg_chip_type) { case MACH64_CFG_CHIP_TYPE( 'V', 'T' ): switch ((config_chip_id & CFG_CHIP_MAJOR) >> 24) { case 0: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, (config_chip_id & CFG_CHIP_MINOR) ? "ATI-264VT2 (%c%c)" : "ATI-264VT (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_264VT; case 1: case 2: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT3 (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_264VT3; } break; case MACH64_CFG_CHIP_TYPE( 'V', 'U' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT3 (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_264VT3; case MACH64_CFG_CHIP_TYPE( 'V', 'V' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "ATI-264VT4 (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_264VT4; } D_WARN( "DirectFB/Mach64: Unknown VT chip type %c%c (0x%08x)", cfg_chip_type >> 8, cfg_chip_type & 0xFF, config_chip_id ); snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 VT" ); return CHIP_UNKNOWN; } static Mach64ChipType mach64_chip_type_gt( Mach64DriverData *mdrv, GraphicsDeviceInfo *device_info ) { u32 config_chip_id = mach64_in32( mdrv->mmio_base, CONFIG_CHIP_ID ); u32 cfg_chip_type = config_chip_id & CFG_CHIP_TYPE; switch (cfg_chip_type) { case MACH64_CFG_CHIP_TYPE( 'G', 'T' ): switch ((config_chip_id & CFG_CHIP_MAJOR) >> 24) { case 0: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE; case 1: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_II; case 2: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II+ (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_IIPLUS; } break; case MACH64_CFG_CHIP_TYPE( 'G', 'U' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage II+ (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_IIPLUS; case MACH64_CFG_CHIP_TYPE( 'L', 'G' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage LT (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_LT; case MACH64_CFG_CHIP_TYPE( 'G', 'V' ): case MACH64_CFG_CHIP_TYPE( 'G', 'W' ): case MACH64_CFG_CHIP_TYPE( 'G', 'Y' ): case MACH64_CFG_CHIP_TYPE( 'G', 'Z' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage IIC (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_IIC; case MACH64_CFG_CHIP_TYPE( 'G', 'B' ): case MACH64_CFG_CHIP_TYPE( 'G', 'D' ): case MACH64_CFG_CHIP_TYPE( 'G', 'I' ): case MACH64_CFG_CHIP_TYPE( 'G', 'P' ): case MACH64_CFG_CHIP_TYPE( 'G', 'Q' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage Pro (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_PRO; case MACH64_CFG_CHIP_TYPE( 'L', 'B' ): case MACH64_CFG_CHIP_TYPE( 'L', 'D' ): case MACH64_CFG_CHIP_TYPE( 'L', 'I' ): case MACH64_CFG_CHIP_TYPE( 'L', 'P' ): case MACH64_CFG_CHIP_TYPE( 'L', 'Q' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage LT Pro (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_LT_PRO; case MACH64_CFG_CHIP_TYPE( 'G', 'M' ): case MACH64_CFG_CHIP_TYPE( 'G', 'O' ): case MACH64_CFG_CHIP_TYPE( 'G', 'R' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage XL (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_XLXC; case MACH64_CFG_CHIP_TYPE( 'G', 'L' ): case MACH64_CFG_CHIP_TYPE( 'G', 'N' ): case MACH64_CFG_CHIP_TYPE( 'G', 'S' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage XC (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_XLXC; case MACH64_CFG_CHIP_TYPE( 'L', 'M' ): case MACH64_CFG_CHIP_TYPE( 'L', 'N' ): case MACH64_CFG_CHIP_TYPE( 'L', 'R' ): case MACH64_CFG_CHIP_TYPE( 'L', 'S' ): snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "3D Rage Mobility (%c%c)", cfg_chip_type >> 8, cfg_chip_type & 0xFF ); return CHIP_3D_RAGE_MOBILITY; } D_WARN( "DirectFB/Mach64: Unknown GT chip type %c%c (0x%08x)", cfg_chip_type >> 8, cfg_chip_type & 0xFF, config_chip_id ); snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 GT" ); return CHIP_UNKNOWN; } /* exported symbols */ static int driver_probe( CoreGraphicsDevice *device ) { switch (dfb_gfxcard_get_accelerator( device )) { case FB_ACCEL_ATI_MACH64GX: case FB_ACCEL_ATI_MACH64CT: case FB_ACCEL_ATI_MACH64VT: case FB_ACCEL_ATI_MACH64GT: return 1; } return 0; } static void driver_get_info( CoreGraphicsDevice *device, GraphicsDriverInfo *info ) { /* fill driver info structure */ snprintf( info->name, DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH, "ATI Mach64 Driver" ); snprintf( info->vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, "Ville Syrjala" ); info->version.major = 0; info->version.minor = 13; info->driver_data_size = sizeof (Mach64DriverData); info->device_data_size = sizeof (Mach64DeviceData); } static DFBResult driver_init_driver( CoreGraphicsDevice *device, GraphicsDeviceFuncs *funcs, void *driver_data, void *device_data, CoreDFB *core ) { Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; mdrv->mmio_base = (volatile u8*) dfb_gfxcard_map_mmio( device, 0, -1 ); if (!mdrv->mmio_base) return DFB_IO; mdrv->device_data = (Mach64DeviceData*) device_data; mdrv->accelerator = dfb_gfxcard_get_accelerator( device ); funcs->EngineReset = mach64EngineReset; funcs->EngineSync = mach64EngineSync; funcs->CheckState = mach64CheckState; funcs->SetState = mach64SetState; funcs->FillRectangle = mach64FillRectangle; funcs->DrawRectangle = mach64DrawRectangle; /* Set dynamically: funcs->DrawLine, funcs->Blit, funcs->StretchBlit */ switch (mdrv->accelerator) { case FB_ACCEL_ATI_MACH64GT: if (!dfb_config->font_format) dfb_config->font_format = DSPF_ARGB; funcs->FlushTextureCache = mach64FlushTextureCache; funcs->CheckState = mach64GTCheckState; funcs->SetState = mach64GTSetState; funcs->FillTriangle = mach64FillTriangle; case FB_ACCEL_ATI_MACH64VT: mdrv->mmio_base += 0x400; dfb_layers_register( dfb_screens_at( DSCID_PRIMARY ), driver_data, &mach64OverlayFuncs ); break; } return DFB_OK; } static DFBResult driver_init_device( CoreGraphicsDevice *device, GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ) { Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; Mach64DeviceData *mdev = (Mach64DeviceData*) device_data; volatile u8 *mmio = mdrv->mmio_base; /* fill device info */ device_info->caps.flags = CCF_CLIPPING; switch (mdrv->accelerator) { case FB_ACCEL_ATI_MACH64GT: device_info->caps.drawing = MACH64GT_SUPPORTED_DRAWINGFLAGS; device_info->caps.blitting = MACH64GT_SUPPORTED_BLITTINGFLAGS; device_info->caps.accel = MACH64GT_SUPPORTED_DRAWINGFUNCTIONS | MACH64GT_SUPPORTED_BLITTINGFUNCTIONS; break; default: device_info->caps.drawing = MACH64_SUPPORTED_DRAWINGFLAGS; device_info->caps.blitting = MACH64_SUPPORTED_BLITTINGFLAGS; device_info->caps.accel = MACH64_SUPPORTED_DRAWINGFUNCTIONS | MACH64_SUPPORTED_BLITTINGFUNCTIONS; break; } switch (mdrv->accelerator) { case FB_ACCEL_ATI_MACH64GX: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 GX" ); break; case FB_ACCEL_ATI_MACH64CT: snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Mach64 CT" ); break; case FB_ACCEL_ATI_MACH64VT: mdev->chip = mach64_chip_type_vt( mdrv, device_info ); break; case FB_ACCEL_ATI_MACH64GT: mdev->chip = mach64_chip_type_gt( mdrv, device_info ); /* Max texture size is 1024x1024 */ device_info->limits.surface_max_power_of_two_pixelpitch = 1024; device_info->limits.surface_max_power_of_two_height = 1024; break; } snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "ATI" ); device_info->limits.surface_byteoffset_alignment = 8; device_info->limits.surface_bytepitch_alignment = 16; device_info->limits.surface_pixelpitch_alignment = 8; /* 3D Rage Pro is the first chip that supports auto fast fill/block write. */ if (mdev->chip >= CHIP_3D_RAGE_PRO) { mdev->hw_debug = mach64_in32( mmio, HW_DEBUG ); /* Save original HW_DEBUG. */ mdev->hw_debug_orig = mdev->hw_debug; /* Enable auto fast fill and fast fill/block write scissoring. */ mdev->hw_debug &= ~(AUTO_FF_DIS | INTER_PRIM_DIS); if ((mach64_in32( mmio, CONFIG_STAT0 ) & CFG_MEM_TYPE) == CFG_MEM_TYPE_SGRAM) { /* Enable auto block write and auto color register updates. */ mdev->hw_debug &= ~(AUTO_BLKWRT_DIS | AUTO_BLKWRT_COLOR_DIS); device_info->limits.surface_byteoffset_alignment = 64; device_info->limits.surface_bytepitch_alignment = 64; } } return DFB_OK; } static void driver_close_device( CoreGraphicsDevice *device, void *driver_data, void *device_data ) { Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; Mach64DeviceData *mdev = (Mach64DeviceData*) device_data; volatile u8 *mmio = mdrv->mmio_base; D_DEBUG( "DirectFB/Mach64: FIFO Performance Monitoring:\n" ); D_DEBUG( "DirectFB/Mach64: %9d mach64_waitfifo calls\n", mdev->waitfifo_calls ); D_DEBUG( "DirectFB/Mach64: %9d register writes (mach64_waitfifo sum)\n", mdev->waitfifo_sum ); D_DEBUG( "DirectFB/Mach64: %9d FIFO wait cycles (depends on CPU)\n", mdev->fifo_waitcycles ); D_DEBUG( "DirectFB/Mach64: %9d IDLE wait cycles (depends on CPU)\n", mdev->idle_waitcycles ); D_DEBUG( "DirectFB/Mach64: %9d FIFO space cache hits(depends on CPU)\n", mdev->fifo_cache_hits ); D_DEBUG( "DirectFB/Mach64: Conclusion:\n" ); D_DEBUG( "DirectFB/Mach64: Average register writes/mach64_waitfifo" "call:%.2f\n", mdev->waitfifo_sum/(float)(mdev->waitfifo_calls) ); D_DEBUG( "DirectFB/Mach64: Average wait cycles/mach64_waitfifo call:" " %.2f\n", mdev->fifo_waitcycles/(float)(mdev->waitfifo_calls) ); D_DEBUG( "DirectFB/Mach64: Average fifo space cache hits: %02d%%\n", (int)(100 * mdev->fifo_cache_hits/ (float)(mdev->waitfifo_calls)) ); switch (mdrv->accelerator) { case FB_ACCEL_ATI_MACH64GT: mach64_waitfifo( mdrv, mdev, 1 ); mach64_out32( mmio, SCALE_3D_CNTL, 0 ); case FB_ACCEL_ATI_MACH64VT: mach64_waitfifo( mdrv, mdev, 1 ); mach64_out32( mmio, OVERLAY_SCALE_CNTL, 0 ); break; } if (mdev->chip >= CHIP_3D_RAGE_PRO) { /* Restore original HW_DEBUG. */ mach64_out32( mmio, HW_DEBUG, mdev->hw_debug_orig ); } } static void driver_close_driver( CoreGraphicsDevice *device, void *driver_data ) { Mach64DriverData *mdrv = (Mach64DriverData*) driver_data; switch (mdrv->accelerator) { case FB_ACCEL_ATI_MACH64VT: case FB_ACCEL_ATI_MACH64GT: mdrv->mmio_base -= 0x400; break; } dfb_gfxcard_unmap_mmio( device, mdrv->mmio_base, -1 ); }