/* (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 "savage.h" #include "savage_bci.h" #include "savage3d.h" #include "mmio.h" #include "savage_streams_old.h" /* required implementations */ static DFBResult savage3DEngineSync( void *drv, void *dev ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; savage3D_waitidle( sdrv, sdev ); return DFB_OK; } #define SAVAGE3D_DRAWING_FLAGS \ (DSDRAW_NOFX) #define SAVAGE3D_DRAWING_FUNCTIONS \ (DFXL_FILLRECTANGLE | DFXL_DRAWRECTANGLE | DFXL_DRAWLINE) #define SAVAGE3D_BLITTING_FLAGS \ (DSBLIT_SRC_COLORKEY) #define SAVAGE3D_BLITTING_FUNCTIONS \ (DFXL_BLIT) static inline void savage3D_validate_gbd( Savage3DDriverData *sdrv, Savage3DDeviceData *sdev, CardState *state ) { u32 BitmapDescriptor; CoreSurface *destination; int bpp; if (sdev->v_gbd) return; destination = state->destination; bpp = DFB_BYTES_PER_PIXEL(destination->config.format); BitmapDescriptor = BCI_BD_BW_DISABLE | 8 | 1; BCI_BD_SET_BPP( BitmapDescriptor, bpp * 8 ); BCI_BD_SET_STRIDE( BitmapDescriptor, state->dst.pitch / bpp ); /* strange effects if we don't wait here for the Savage3D being idle */ savage3D_waitidle( sdrv, sdev ); savage3D_waitfifo( sdrv, sdev, 4 ); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 ); BCI_SEND( state->dst.offset ); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 ); BCI_SEND( BitmapDescriptor ); sdev->v_gbd = 1; } static inline void savage3D_validate_pbd( Savage3DDriverData *sdrv, Savage3DDeviceData *sdev, CardState *state ) { u32 BitmapDescriptor; CoreSurface *source; int bpp; if (sdev->v_pbd) return; source = state->source; bpp = DFB_BYTES_PER_PIXEL(source->config.format); BitmapDescriptor = BCI_BD_BW_DISABLE; BCI_BD_SET_BPP( BitmapDescriptor, bpp * 8 ); BCI_BD_SET_STRIDE( BitmapDescriptor, state->src.pitch / bpp ); savage3D_waitfifo( sdrv, sdev, 4 ); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_PBD1 ); BCI_SEND( state->src.offset ); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_PBD2 ); BCI_SEND( BitmapDescriptor ); sdev->v_pbd = 1; } static inline void savage3D_validate_color( Savage3DDriverData *sdrv, Savage3DDeviceData *sdev, CardState *state ) { if (sdev->v_color) return; savage3D_waitfifo( sdrv, sdev, 2 ); BCI_SEND( BCI_CMD_NOP | BCI_CMD_SEND_COLOR ); switch (state->destination->config.format) { case DSPF_A8: BCI_SEND( state->color.a ); break; case DSPF_ARGB1555: BCI_SEND( PIXEL_ARGB1555(state->color.a, state->color.r, state->color.g, state->color.b) ); break; case DSPF_RGB16: BCI_SEND( PIXEL_RGB16(state->color.r, state->color.g, state->color.b) ); break; case DSPF_RGB32: BCI_SEND( PIXEL_RGB32(state->color.r, state->color.g, state->color.b) ); break; case DSPF_ARGB: BCI_SEND( PIXEL_ARGB(state->color.a, state->color.r, state->color.g, state->color.b) ); break; default: D_ONCE( "unsupported destination format" ); break; } sdev->v_color = 1; } static inline void savage3D_set_clip( Savage3DDriverData *sdrv, Savage3DDeviceData *sdev, DFBRegion *clip ) { savage3D_waitfifo( sdrv, sdev, 3 ); BCI_SEND( BCI_CMD_NOP | BCI_CMD_CLIP_NEW ); BCI_SEND( BCI_CLIP_TL( clip->y1, clip->x1 ) ); BCI_SEND( BCI_CLIP_BR( clip->y2, clip->x2 ) ); } static void savage3DCheckState( void *drv, void *dev, CardState *state, DFBAccelerationMask accel ) { switch (state->destination->config.format) { case DSPF_ARGB1555: case DSPF_RGB16: case DSPF_RGB32: case DSPF_ARGB: break; default: return; } if (DFB_DRAWING_FUNCTION( accel )) { if (state->drawingflags & ~SAVAGE3D_DRAWING_FLAGS) return; state->accel |= SAVAGE3D_DRAWING_FUNCTIONS; } else { if (state->source->config.format != state->destination->config.format) return; if (state->blittingflags & ~SAVAGE3D_BLITTING_FLAGS) return; state->accel |= SAVAGE3D_BLITTING_FUNCTIONS; } } static void savage3DSetState( void *drv, void *dev, GraphicsDeviceFuncs *funcs, CardState *state, DFBAccelerationMask accel ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; if (state->mod_hw) { if (state->mod_hw & SMF_DESTINATION) sdev->v_gbd = sdev->v_color = 0; else if (state->mod_hw & SMF_COLOR) sdev->v_color = 0; if (state->mod_hw & SMF_SOURCE) sdev->v_pbd = 0; } savage3D_validate_gbd( sdrv, sdev, state ); switch (accel) { case DFXL_FILLRECTANGLE: case DFXL_DRAWRECTANGLE: case DFXL_DRAWLINE: case DFXL_FILLTRIANGLE: savage3D_validate_color( sdrv, sdev, state ); state->set |= SAVAGE3D_DRAWING_FUNCTIONS; break; case DFXL_BLIT: case DFXL_STRETCHBLIT: savage3D_validate_pbd( sdrv, sdev, state ); state->set |= SAVAGE3D_BLITTING_FUNCTIONS; break; default: D_BUG( "unexpected drawing/blitting function!" ); return; } if (state->mod_hw & SMF_BLITTING_FLAGS) { if (state->blittingflags & DSBLIT_SRC_COLORKEY) sdev->Cmd_Src_Transparent = BCI_CMD_SRC_TRANSPARENT | BCI_CMD_SEND_COLOR; else sdev->Cmd_Src_Transparent = 0; } if (state->mod_hw & SMF_CLIP) savage3D_set_clip( sdrv, sdev, &state->clip ); if (state->mod_hw & SMF_SRC_COLORKEY) sdev->src_colorkey = state->src_colorkey; state->mod_hw = 0; } static bool savage3DFillRectangle( void *drv, void *dev, DFBRectangle *rect ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; savage3D_waitfifo( sdrv, sdev, 3 ); BCI_SEND( BCI_CMD_RECT | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_X_Y(rect->x, rect->y) ); BCI_SEND( BCI_W_H(rect->w, rect->h) ); return true; } static bool savage3DDrawRectangle( void *drv, void *dev, DFBRectangle *rect ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; savage3D_waitfifo( sdrv, sdev, 12 ); /* first line */ BCI_SEND( BCI_CMD_RECT | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_X_Y( rect->x, rect->y) ); BCI_SEND( BCI_W_H( 1 , rect->h) ); /* second line */ BCI_SEND( BCI_CMD_RECT | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_X_Y( rect->x, rect->y) ); BCI_SEND( BCI_W_H( rect->w , 1 ) ); /* third line */ BCI_SEND( BCI_CMD_RECT | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_X_Y( rect->x, rect->y+rect->h-1 ) ); BCI_SEND( BCI_W_H( rect->w , 1 ) ); /* fourth line */ BCI_SEND( BCI_CMD_RECT | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_X_Y( rect->x+rect->w-1, rect->y ) ); BCI_SEND( BCI_W_H( 1 , rect->h ) ); return true; } static bool savage3DDrawLine( void *drv, void *dev, DFBRegion *line ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; int dx, dy; int min, max, xp, yp, ym; dx = line->x2 - line->x1; dy = line->y2 - line->y1; xp = (dx >= 0); if (!xp) dx = -dx; yp = (dy >= 0); if (!yp) dy = -dy; ym = (dy > dx); if (ym) { max = dy + 1; min = dx; } else { max = dx + 1; min = dy; } savage3D_waitfifo( sdrv, sdev, 4 ); BCI_SEND( BCI_CMD_LINE_LAST_PIXEL | BCI_CMD_CLIP_CURRENT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID | (0xcc << 16) ); BCI_SEND( BCI_LINE_X_Y( line->x1, line->y1 ) ); BCI_SEND( BCI_LINE_STEPS( 2 * (min - max), 2 * min ) ); BCI_SEND( BCI_LINE_MISC( max, ym, xp, yp, 2 * min - max ) ); return true; } static bool savage3DFillTriangle( void *drv, void *dev, DFBTriangle *tri ) { return false; } static bool savage3DBlit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) { Savage3DDriverData *sdrv = (Savage3DDriverData*) drv; Savage3DDeviceData *sdev = (Savage3DDeviceData*) dev; u32 cmd = ( BCI_CMD_RECT | sdev->Cmd_Src_Transparent | BCI_CMD_CLIP_CURRENT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_PBD_COLOR | (0xcc << 16) ); if (dx < rect->x) { cmd |= BCI_CMD_RECT_XP; } else { dx += rect->w - 1; rect->x += rect->w - 1; } if (dy < rect->y) { cmd |= BCI_CMD_RECT_YP; } else { dy += rect->h - 1; rect->y += rect->h - 1; } savage3D_waitfifo( sdrv, sdev, sdev->Cmd_Src_Transparent ? 5 : 4 ); BCI_SEND( cmd ); /* we always have to send the colorkey, but at least it does not clobber the fill color */ if (sdev->Cmd_Src_Transparent) BCI_SEND( sdev->src_colorkey ); BCI_SEND( BCI_X_Y( rect->x, rect->y ) ); BCI_SEND( BCI_X_Y( dx, dy ) ); BCI_SEND( BCI_W_H( rect->w, rect->h ) ); return true; } static bool savage3DStretchBlit( void *drv, void *dev, DFBRectangle *sr, DFBRectangle *dr ) { return false; } static void savage3DAfterSetVar( void *drv, void *dev ) { } /* exported symbols */ void savage3d_get_info( CoreGraphicsDevice *device, GraphicsDriverInfo *info ) { info->version.major = 0; info->version.minor = 3; info->driver_data_size = sizeof (Savage3DDriverData); info->device_data_size = sizeof (Savage3DDeviceData); } DFBResult savage3d_init_driver( CoreGraphicsDevice *device, GraphicsDeviceFuncs *funcs, void *driver_data ) { funcs->CheckState = savage3DCheckState; funcs->SetState = savage3DSetState; funcs->EngineSync = savage3DEngineSync; funcs->AfterSetVar = savage3DAfterSetVar; funcs->FillRectangle = savage3DFillRectangle; funcs->DrawRectangle = savage3DDrawRectangle; funcs->DrawLine = savage3DDrawLine; funcs->FillTriangle = savage3DFillTriangle; funcs->Blit = savage3DBlit; funcs->StretchBlit = savage3DStretchBlit; return DFB_OK; } DFBResult savage3d_init_device( CoreGraphicsDevice *device, GraphicsDeviceInfo *device_info, void *driver_data, void *device_data ) { SavageDriverData *sdrv = (SavageDriverData*) driver_data; volatile u8 *mmio = sdrv->mmio_base; unsigned long cobIndex; /* size index */ unsigned long cobSize; /* size in bytes */ unsigned long cobOffset; /* offset in frame buffer */ /* fill device info */ snprintf( device_info->name, DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Savage3D Series" ); snprintf( device_info->vendor, DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "S3" ); device_info->caps.flags = CCF_CLIPPING; device_info->caps.accel = SAVAGE3D_DRAWING_FUNCTIONS | SAVAGE3D_BLITTING_FUNCTIONS; device_info->caps.drawing = SAVAGE3D_DRAWING_FLAGS; device_info->caps.blitting = SAVAGE3D_BLITTING_FLAGS; device_info->limits.surface_byteoffset_alignment = 2048; device_info->limits.surface_pixelpitch_alignment = 32; cobIndex = 7; cobSize = 0x400 << cobIndex; cobOffset = dfb_gfxcard_reserve_memory( device, cobSize ); /* savage_out32( 0x8504, 0x00008000 ); */ /* Disable BCI */ savage_out32( mmio, 0x48C18, savage_in32( mmio, 0x48C18 ) & 0x3FF0); /* Setup BCI command overflow buffer */ savage_out32( mmio, 0x48C14, (cobOffset >> 11) | (cobIndex << 29)); /* Program shadow status update. */ savage_out32( mmio, 0x48C10, 0x78207220); savage_out32( mmio, 0x48C0C, 0); /* Enable BCI and command overflow buffer */ savage_out32( mmio, 0x48C18, savage_in32( mmio, 0x48C18 ) | 0x0C); return DFB_OK; } void savage3d_close_device( CoreGraphicsDevice *device, void *driver_data, void *device_data ) { } void savage3d_close_driver( CoreGraphicsDevice *device, void *driver_data ) { }