diff options
Diffstat (limited to 'Source/DirectFB/gfxdrivers/tdfx/tdfx.c')
-rwxr-xr-x | Source/DirectFB/gfxdrivers/tdfx/tdfx.c | 884 |
1 files changed, 884 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/tdfx/tdfx.c b/Source/DirectFB/gfxdrivers/tdfx/tdfx.c new file mode 100755 index 0000000..fdc03fc --- /dev/null +++ b/Source/DirectFB/gfxdrivers/tdfx/tdfx.c @@ -0,0 +1,884 @@ +/* + (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 <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> and + Claudio Ciccani <klan@users.sf.net>. + + 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 <config.h> + +#include <dfb_types.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include <sys/mman.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#include <fbdev/fb.h> + +#include <directfb.h> + +#include <direct/messages.h> + +#include <core/coredefs.h> +#include <core/coretypes.h> + +#include <core/state.h> +#include <core/gfxcard.h> +#include <core/surface.h> + +#include <gfx/convert.h> +#include <gfx/util.h> +#include <misc/conf.h> + +#include <core/graphics_driver.h> + + +DFB_GRAPHICS_DRIVER( tdfx ) + +#include "tdfx.h" + +static bool tdfxFillRectangle2D( void *drv, void *dev, DFBRectangle *rect ); +static bool tdfxFillRectangle3D( void *drv, void *dev, DFBRectangle *rect ); +static bool tdfxFillTriangle2D ( void *drv, void *dev, DFBTriangle *tri ); +static bool tdfxFillTriangle3D ( void *drv, void *dev, DFBTriangle *tri ); +static bool tdfxDrawLine2D ( void *drv, void *dev, DFBRegion *line ); +//static void tdfxDrawLine3D ( void *drv, void *dev, DFBRegion *line ); + +typedef struct { + /* for fifo/performance monitoring */ + unsigned int fifo_space; + + unsigned int waitfifo_sum; + unsigned int waitfifo_calls; + unsigned int fifo_waitcycles; + unsigned int idle_waitcycles; + unsigned int fifo_cache_hits; + + /* state validation */ + int v_destination2D; + int v_destination3D; + int v_color1; + int v_colorFore; + int v_alphaMode; + int v_source2D; + int v_srcColorkey; + int v_commandExtra; +} TDFXDeviceData; + +typedef struct { + volatile u8 *mmio_base; + Voodoo2D *voodoo2D; + Voodoo3D *voodoo3D; +} TDFXDriverData; + + + +static inline void tdfx_waitfifo( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + unsigned int space ) +{ + int timeout = 1000000; + + tdev->waitfifo_calls++; + tdev->waitfifo_sum += space; + + if (tdev->fifo_space < space) { + while (timeout--) { + tdev->fifo_waitcycles++; + + tdev->fifo_space = (tdrv->voodoo2D->status & 0x3f); + if (tdev->fifo_space >= space) + break; + + } + } else { + tdev->fifo_cache_hits++; + } + + tdev->fifo_space -= space; + + if (!timeout) + D_WARN( "timeout during waitfifo!" ); +} + +static inline void tdfx_waitidle( TDFXDriverData *tdrv, + TDFXDeviceData *tdev ) +{ + int i = 0; + int timeout = 1000000; + +// tdfx_waitfifo( tdrv, tdev, 1 ); + +// voodoo3D->nopCMD = 0; + + while (timeout--) { + tdev->idle_waitcycles++; + + i = (tdrv->voodoo2D->status & (0xF << 7)) ? 0 : i + 1; + if (i == 3) + return; + + } + + D_BUG( "timeout during waitidle!\n"); +} + + +static int blitFormat[] = { + 2, /* DSPF_ARGB1555 */ + 3, /* DSPF_RGB16 */ + 4, /* DSPF_RGB24 */ + 5, /* DSPF_RGB32 */ + 5, /* DSPF_ARGB */ + 0 /* DSPF_A8 */ +}; + +static inline void tdfx_validate_source2D( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + CoreSurface *source = state->source; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + if (tdev->v_source2D) + return; + + tdfx_waitfifo( tdrv, tdev, 2 ); + + voodoo2D->srcBaseAddr = state->src.offset & 0xFFFFFF; + voodoo2D->srcFormat = (state->src.pitch & 0x3FFF) | + (blitFormat[DFB_PIXELFORMAT_INDEX(source->config.format)] << 16); + + tdev->v_source2D = 1; +} + +static inline void tdfx_validate_destination2D( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + CoreSurface *destination = state->destination; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + if (tdev->v_destination2D) + return; + + tdfx_waitfifo( tdrv, tdev, 2 ); + + voodoo2D->dstBaseAddr = state->dst.offset; + voodoo2D->dstFormat = (state->dst.pitch & 0x3FFF) | + (blitFormat[DFB_PIXELFORMAT_INDEX(destination->config.format)] << 16); + + tdev->v_destination2D = 1; +} + +static inline void tdfx_validate_destination3D( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + CoreSurface *destination = state->destination; + Voodoo3D *voodoo3D = tdrv->voodoo3D; + + u32 lfbmode = TDFX_LFBMODE_PIXEL_PIPELINE_ENABLE; + u32 fbzMode = (1 << 9) | 1; + + if (tdev->v_destination3D) + return; + + switch (destination->config.format) { + case DSPF_ARGB1555: + lfbmode |= TDFX_LFBMODE_RGB555; + break; + case DSPF_RGB16: + lfbmode |= TDFX_LFBMODE_RGB565; + break; + case DSPF_RGB32: + lfbmode |= TDFX_LFBMODE_RGB0888; + break; + case DSPF_ARGB: + fbzMode |= (1 << 10); + lfbmode |= TDFX_LFBMODE_ARGB8888; + break; + default: + D_BUG( "unexpected pixelformat!" ); + break; + } + + tdfx_waitfifo( tdrv, tdev, 4 ); + + voodoo3D->lfbMode = lfbmode; + voodoo3D->fbzMode = fbzMode; + voodoo3D->colBufferAddr = state->dst.offset; + voodoo3D->colBufferStride = state->dst.pitch; + + tdev->v_destination3D = 1; +} + +static inline void tdfx_validate_color1( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + if (tdev->v_color1) + return; + + tdfx_waitfifo( tdrv, tdev, 1 ); + + tdrv->voodoo3D->color1 = PIXEL_ARGB( state->color.a, + state->color.r, + state->color.g, + state->color.b ); + + tdev->v_color1 = 1; +} + +static inline void tdfx_validate_colorFore( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + if (tdev->v_colorFore) + return; + + tdfx_waitfifo( tdrv, tdev, 1 ); + + switch (state->destination->config.format) { + case DSPF_A8: + tdrv->voodoo2D->colorFore = state->color.a; + break; + case DSPF_ARGB1555: + tdrv->voodoo2D->colorFore = PIXEL_ARGB1555( state->color.a, + state->color.r, + state->color.g, + state->color.b ); + break; + case DSPF_RGB16: + tdrv->voodoo2D->colorFore = PIXEL_RGB16( state->color.r, + state->color.g, + state->color.b ); + break; + case DSPF_RGB24: + case DSPF_RGB32: + tdrv->voodoo2D->colorFore = PIXEL_RGB32( state->color.r, + state->color.g, + state->color.b ); + break; + case DSPF_ARGB: + tdrv->voodoo2D->colorFore = PIXEL_ARGB( state->color.a, + state->color.r, + state->color.g, + state->color.b ); + break; + default: + D_BUG( "unexpected pixelformat!" ); + break; + } + + tdev->v_colorFore = 1; +} + +static inline void tdfx_validate_alphaMode( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + static int tdfxBlendFactor[] = { + 0, + 0x0, /* DSBF_ZERO */ + 0x4, /* DSBF_ONE */ + 0x2, /* DSBF_SRCCOLOR */ + 0x6, /* DSBF_INVSRCCOLOR */ + 0x1, /* DSBF_SRCALPHA */ + 0x5, /* DSBF_INVSRCALPHA */ + 0x3, /* DSBF_DESTALPHA */ + 0x7, /* DSBF_INVDESTALPHA */ + 0x2, /* DSBF_DESTCOLOR */ + 0x6, /* DSBF_INVDESTCOLOR */ + 0xF /* DSBF_SRCALPHASAT */ + }; + + if (tdev->v_alphaMode) + return; + + tdfx_waitfifo( tdrv, tdev, 1 ); + + tdrv->voodoo3D->alphaMode = TDFX_ALPHAMODE_BLEND_ENABLE | + (tdfxBlendFactor[state->src_blend] << 8) | + (tdfxBlendFactor[state->src_blend] << 16) | + (tdfxBlendFactor[state->dst_blend] << 12) | + (tdfxBlendFactor[state->dst_blend] << 20); + + tdev->v_alphaMode = 1; +} + +static inline void tdfx_validate_srcColorkey( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + if (tdev->v_srcColorkey) + return; + + tdfx_waitfifo( tdrv, tdev, 2 ); + + voodoo2D->srcColorkeyMin = + voodoo2D->srcColorkeyMax = state->src_colorkey; + + tdev->v_srcColorkey = 1; +} + +static inline void tdfx_validate_commandExtra( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + CardState *state ) +{ + if (tdev->v_commandExtra) + return; + + tdfx_waitfifo( tdrv, tdev, 1 ); + + if (state->blittingflags & DSBLIT_SRC_COLORKEY) + tdrv->voodoo2D->commandExtra = 1; + else + tdrv->voodoo2D->commandExtra = 0; + + tdev->v_commandExtra = 1; +} + + + +static inline void tdfx_set_clip( TDFXDriverData *tdrv, + TDFXDeviceData *tdev, + DFBRegion *clip ) +{ + Voodoo2D *voodoo2D = tdrv->voodoo2D; + Voodoo3D *voodoo3D = tdrv->voodoo3D; + + tdfx_waitfifo( tdrv, tdev, 4 ); + + voodoo2D->clip0Min = ((clip->y1 & 0xFFF) << 16) | + (clip->x1 & 0xFFF); + + voodoo2D->clip0Max = (((clip->y2+1) & 0xFFF) << 16) | + ((clip->x2+1) & 0xFFF); + + voodoo3D->clipLeftRight = ((clip->x1 & 0xFFF) << 16) | + ((clip->x2+1) & 0xFFF); + + voodoo3D->clipTopBottom = ((clip->y1 & 0xFFF) << 16) | + ((clip->y2+1) & 0xFFF); +} + + + +/* required implementations */ + +static DFBResult tdfxEngineSync( void *drv, void *dev ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + + tdfx_waitidle( tdrv, tdev ); + + return DFB_OK; +} + +#define TDFX_SUPPORTED_DRAWINGFLAGS \ + (DSDRAW_BLEND) + +#define TDFX_SUPPORTED_DRAWINGFUNCTIONS \ + (DFXL_FILLRECTANGLE | DFXL_DRAWLINE | DFXL_FILLTRIANGLE) + +#define TDFX_SUPPORTED_BLITTINGFLAGS \ + (DSBLIT_SRC_COLORKEY) + +#define TDFX_SUPPORTED_BLITTINGFUNCTIONS \ + (DFXL_BLIT | DFXL_STRETCHBLIT) + + +static void tdfxCheckState( void *drv, void *dev, + CardState *state, DFBAccelerationMask accel ) +{ + /* check for the special drawing function that does not support + the usually supported drawingflags */ + if (accel == DFXL_DRAWLINE && state->drawingflags != DSDRAW_NOFX) + return; + + /* if there are no other drawing flags than the supported */ + if (!(state->drawingflags & ~TDFX_SUPPORTED_DRAWINGFLAGS)) + state->accel |= TDFX_SUPPORTED_DRAWINGFUNCTIONS; + + /* if there are no other blitting flags than the supported + and the source and destination formats are the same */ + if (!(state->blittingflags & ~TDFX_SUPPORTED_BLITTINGFLAGS) && + state->source && state->source->config.format != DSPF_RGB24) + state->accel |= TDFX_SUPPORTED_BLITTINGFUNCTIONS; +} + +static void tdfxSetState( void *drv, void *dev, + GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + + if (state->mod_hw & SMF_DESTINATION) + tdev->v_destination2D = tdev->v_destination3D = tdev->v_colorFore = 0; + + if (state->mod_hw & SMF_SOURCE) + tdev->v_source2D = 0; + + if (state->mod_hw & (SMF_DST_BLEND | SMF_SRC_BLEND)) + tdev->v_alphaMode = 0; + + if (state->mod_hw & SMF_COLOR) + tdev->v_color1 = tdev->v_colorFore = 0; + + if (state->mod_hw & SMF_SRC_COLORKEY) + tdev->v_srcColorkey = 0; + + if (state->mod_hw & SMF_BLITTING_FLAGS) + tdev->v_commandExtra = 0; + + switch (accel) { + case DFXL_FILLRECTANGLE: + case DFXL_DRAWLINE: + case DFXL_FILLTRIANGLE: + if (state->drawingflags & DSDRAW_BLEND) { + tdfx_validate_color1( tdrv, tdev, state ); + tdfx_validate_alphaMode( tdrv, tdev, state ); + tdfx_validate_destination3D( tdrv, tdev, state ); + + funcs->FillRectangle = tdfxFillRectangle3D; + funcs->FillTriangle = tdfxFillTriangle3D; + } else { + tdfx_validate_colorFore( tdrv, tdev, state ); + tdfx_validate_destination2D( tdrv, tdev, state ); + + funcs->FillRectangle = tdfxFillRectangle2D; + funcs->FillTriangle = tdfxFillTriangle2D; + } + + state->set |= DFXL_FILLRECTANGLE | DFXL_DRAWLINE; + break; + + case DFXL_BLIT: + case DFXL_STRETCHBLIT: + if (state->blittingflags & DSBLIT_SRC_COLORKEY) + tdfx_validate_srcColorkey( tdrv, tdev, state ); + + tdfx_validate_commandExtra( tdrv, tdev, state ); + tdfx_validate_source2D( tdrv, tdev, state ); + tdfx_validate_destination2D( tdrv, tdev, state ); + + state->set |= DFXL_BLIT | DFXL_STRETCHBLIT; + break; + + default: + D_BUG( "unexpected drawing/blitting function" ); + break; + } + + if (state->mod_hw & SMF_CLIP) + tdfx_set_clip( tdrv, tdev, &state->clip ); + + state->mod_hw = 0; +} + +static bool tdfxFillRectangle2D( void *drv, void *dev, DFBRectangle *rect ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + tdfx_waitfifo( tdrv, tdev, 3 ); + + voodoo2D->dstXY = ((rect->y & 0x1FFF) << 16) | (rect->x & 0x1FFF); + voodoo2D->dstSize = ((rect->h & 0x1FFF) << 16) | (rect->w & 0x1FFF); + + voodoo2D->command = 5 | (1 << 8) | (0xCC << 24); + + return true; +} + +static bool tdfxFillRectangle3D( void *drv, void *dev, DFBRectangle *rect ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo3D *voodoo3D = tdrv->voodoo3D; + + tdfx_waitfifo( tdrv, tdev, 10 ); + + voodoo3D->vertexAx = S12_4(rect->x); + voodoo3D->vertexAy = S12_4(rect->y); + + voodoo3D->vertexBx = S12_4(rect->x); + voodoo3D->vertexBy = S12_4(rect->y + rect->h); + + voodoo3D->vertexCx = S12_4(rect->x + rect->w); + voodoo3D->vertexCy = S12_4(rect->y + rect->h); + + voodoo3D->triangleCMD = (1 << 31); + + + voodoo3D->vertexBx = S12_4(rect->x + rect->w); + voodoo3D->vertexBy = S12_4(rect->y); + + voodoo3D->triangleCMD = 0; + + return true; +} + +static bool tdfxDrawRectangle( void *drv, void *dev, DFBRectangle *rect ) +{ + return false; +} + +static bool tdfxDrawLine2D( void *drv, void *dev, DFBRegion *line ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + tdfx_waitfifo( tdrv, tdev, 5 ); + + voodoo2D->srcXY = ((line->y1 & 0x1FFF) << 16) | (line->x1 & 0x1FFF); + voodoo2D->dstXY = ((line->y2 & 0x1FFF) << 16) | (line->x2 & 0x1FFF); + voodoo2D->command = 6 | (1 << 8) | (0xCC << 24); + + return true; +} + +/*static bool tdfxDrawLine3D( void *drv, void *dev, DFBRegion *line ) +{ + int xl, xr, yb, yt; + + if (line->x1 < line->x2) { + xl = -8; + xr = 8; + } + else { + xl = 8; + xr = -8; + } + + if (line->y1 < line->y2) { + yt = -8; + yb = 8; + } + else { + yt = 8; + yb = -8; + } + + tdfx_waitfifo( 10 ); + + voodoo3D->vertexAx = S12_4_( line->x1, xl ); + voodoo3D->vertexAy = S12_4_( line->y1, yt ); + + voodoo3D->vertexBx = S12_4_( line->x2, xl ); + voodoo3D->vertexBy = S12_4_( line->y2, yb ); + + voodoo3D->vertexCx = S12_4_( line->x2, xr ); + voodoo3D->vertexCy = S12_4_( line->y2, yb ); + + voodoo3D->triangleCMD = (1 << 31); + + + voodoo3D->vertexBx = S12_4_( line->x1, xr ); + voodoo3D->vertexBy = S12_4_( line->y1, yt ); + + voodoo3D->triangleCMD = 0; + + return true; +}*/ + +static bool tdfxFillTriangle2D( void *drv, void *dev, DFBTriangle *tri ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + tdfx_waitfifo( tdrv, tdev, 7 ); + + dfb_sort_triangle( tri ); + + voodoo2D->srcXY = ((tri->y1 & 0x1FFF) << 16) | (tri->x1 & 0x1FFF); + voodoo2D->command = 8 | (1 << 8) | (0xCC << 24); + + if (tri->x2 < tri->x3) { + voodoo2D->launchArea[0] = ((tri->y2 & 0x1FFF) << 16) | (tri->x2 & 0x1FFF); + voodoo2D->launchArea[1] = ((tri->y3 & 0x1FFF) << 16) | (tri->x3 & 0x1FFF); + voodoo2D->launchArea[2] = ((tri->y2 & 0x1FFF) << 16) | (tri->x2 & 0x1FFF); + + } else { + voodoo2D->launchArea[0] = ((tri->y3 & 0x1FFF) << 16) | (tri->x3 & 0x1FFF); + voodoo2D->launchArea[1] = ((tri->y2 & 0x1FFF) << 16) | (tri->x2 & 0x1FFF); + voodoo2D->launchArea[2] = ((tri->y3 & 0x1FFF) << 16) | (tri->x3 & 0x1FFF); + + } + + return true; +} + +static bool tdfxFillTriangle3D( void *drv, void *dev, DFBTriangle *tri ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo3D *voodoo3D = tdrv->voodoo3D; + + tdfx_waitfifo( tdrv, tdev, 7 ); + + dfb_sort_triangle( tri ); + + voodoo3D->vertexAx = S12_4(tri->x1); + voodoo3D->vertexAy = S12_4(tri->y1); + + voodoo3D->vertexBx = S12_4(tri->x2); + voodoo3D->vertexBy = S12_4(tri->y2); + + voodoo3D->vertexCx = S12_4(tri->x3); + voodoo3D->vertexCy = S12_4(tri->y3); + + voodoo3D->triangleCMD = (1 << 31); + + voodoo3D->triangleCMD = 0; + + return true; +} + +static bool tdfxBlit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + u32 cmd = 1 | (1 <<8) | (0xCC << 24);//SST_2D_GO | SST_2D_SCRNTOSCRNBLIT | (ROP_COPY << 24); + + if (rect->x <= dx) { + cmd |= (1 << 14);//SST_2D_X_RIGHT_TO_LEFT; + rect->x += rect->w-1; + dx += rect->w-1; + } + if (rect->y <= dy) { + cmd |= (1 << 15);//SST_2D_Y_BOTTOM_TO_TOP; + rect->y += rect->h-1; + dy += rect->h-1; + } + + + tdfx_waitfifo( tdrv, tdev, 4 ); + + voodoo2D->srcXY = ((rect->y & 0x1FFF) << 16) | (rect->x & 0x1FFF); + voodoo2D->dstXY = ((dy & 0x1FFF) << 16) | (dx & 0x1FFF); + voodoo2D->dstSize = ((rect->h & 0x1FFF) << 16) | (rect->w & 0x1FFF); + + voodoo2D->command = cmd; + + return true; +} + +static bool tdfxStretchBlit( void *drv, void *dev, DFBRectangle *sr, DFBRectangle *dr ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) drv; + TDFXDeviceData *tdev = (TDFXDeviceData*) dev; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + + tdfx_waitfifo( tdrv, tdev, 5 ); + + voodoo2D->srcXY = ((sr->y & 0x1FFF) << 16) | (sr->x & 0x1FFF); + voodoo2D->srcSize = ((sr->h & 0x1FFF) << 16) | (sr->w & 0x1FFF); + + voodoo2D->dstXY = ((dr->y & 0x1FFF) << 16) | (dr->x & 0x1FFF); + voodoo2D->dstSize = ((dr->h & 0x1FFF) << 16) | (dr->w & 0x1FFF); + + voodoo2D->command = 2 | (1 << 8) | (0xCC << 24); + + return true; +} + +/* exported symbols */ + +static int +driver_probe( CoreGraphicsDevice *device ) +{ + switch (dfb_gfxcard_get_accelerator( device )) { + case FB_ACCEL_3DFX_BANSHEE: /* Banshee/Voodoo3 */ + 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, + "3Dfx Voodoo 3/4/5/Banshee Driver" ); + + snprintf( info->vendor, + DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH, + "directfb.org" ); + + info->version.major = 0; + info->version.minor = 1; + + info->driver_data_size = sizeof (TDFXDriverData); + info->device_data_size = sizeof (TDFXDeviceData); +} + +static DFBResult +driver_init_driver( CoreGraphicsDevice *device, + GraphicsDeviceFuncs *funcs, + void *driver_data, + void *device_data, + CoreDFB *core ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) driver_data; + + tdrv->mmio_base = (volatile u8*) dfb_gfxcard_map_mmio( device, 0, -1 ); + if (!tdrv->mmio_base) + return DFB_IO; + + tdrv->voodoo2D = (Voodoo2D*)(tdrv->mmio_base + 0x100000); + tdrv->voodoo3D = (Voodoo3D*)(tdrv->mmio_base + 0x200000); + + funcs->CheckState = tdfxCheckState; + funcs->SetState = tdfxSetState; + funcs->EngineSync = tdfxEngineSync; + + funcs->DrawRectangle = tdfxDrawRectangle; + funcs->DrawLine = tdfxDrawLine2D; + funcs->Blit = tdfxBlit; + funcs->StretchBlit = tdfxStretchBlit; + + return DFB_OK; +} + + +static DFBResult +driver_init_device( CoreGraphicsDevice *device, + GraphicsDeviceInfo *device_info, + void *driver_data, + void *device_data ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) driver_data; + TDFXDeviceData *tdev = (TDFXDeviceData*) device_data; + Voodoo2D *voodoo2D = tdrv->voodoo2D; + Voodoo3D *voodoo3D = tdrv->voodoo3D; + + /* fill device info */ + snprintf( device_info->name, + DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "Voodoo 3/4/5/Banshee" ); + + snprintf( device_info->vendor, + DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "3Dfx" ); + + + device_info->caps.flags = CCF_CLIPPING; + device_info->caps.accel = TDFX_SUPPORTED_DRAWINGFUNCTIONS | + TDFX_SUPPORTED_BLITTINGFUNCTIONS; + device_info->caps.drawing = TDFX_SUPPORTED_DRAWINGFLAGS; + device_info->caps.blitting = TDFX_SUPPORTED_BLITTINGFLAGS; + + device_info->limits.surface_byteoffset_alignment = 32 * 4; + device_info->limits.surface_pixelpitch_alignment = 32; + + + /* initialize card */ + voodoo2D->status = 0; + voodoo3D->nopCMD = 3; + + tdfx_waitfifo( tdrv, tdev, 6 ); + + voodoo3D->clipLeftRight1 = 0; + voodoo3D->clipTopBottom1 = 0; + + voodoo3D->fbzColorPath = TDFX_FBZCOLORPATH_RGBSELECT_COLOR1 | + TDFX_FBZCOLORPATH_ASELECT_COLOR1; + + voodoo3D->textureMode = 0; + + voodoo2D->commandExtra = 0; + voodoo2D->rop = 0xAAAAAA; + + tdfx_waitfifo( tdrv, tdev, 1 ); /* VOODOO !!! */ + + *((volatile u32*)((volatile u8*) tdrv->mmio_base + 0x10c)) = + 1 << 4 | 1 << 8 | 5 << 12 | 1 << 18 | 5 << 24; + + dfb_config->pollvsync_after = 1; + + return DFB_OK; +} + +static void +driver_close_device( CoreGraphicsDevice *device, + void *driver_data, + void *device_data ) +{ + TDFXDeviceData *tdev = (TDFXDeviceData*) device_data; + TDFXDriverData *tdrv = (TDFXDriverData*) driver_data; + + (void) tdev; + (void) tdrv; + + D_DEBUG( "DirectFB/TDFX: FIFO Performance Monitoring:\n" ); + D_DEBUG( "DirectFB/TDFX: %9d tdfx_waitfifo calls\n", + tdev->waitfifo_calls ); + D_DEBUG( "DirectFB/TDFX: %9d register writes (tdfx_waitfifo sum)\n", + tdev->waitfifo_sum ); + D_DEBUG( "DirectFB/TDFX: %9d FIFO wait cycles (depends on CPU)\n", + tdev->fifo_waitcycles ); + D_DEBUG( "DirectFB/TDFX: %9d IDLE wait cycles (depends on CPU)\n", + tdev->idle_waitcycles ); + D_DEBUG( "DirectFB/TDFX: %9d FIFO space cache hits(depends on CPU)\n", + tdev->fifo_cache_hits ); + D_DEBUG( "DirectFB/TDFX: Conclusion:\n" ); + D_DEBUG( "DirectFB/TDFX: Average register writes/tdfx_waitfifo" + "call:%.2f\n", + tdev->waitfifo_sum/(float)(tdev->waitfifo_calls) ); + D_DEBUG( "DirectFB/TDFX: Average wait cycles/tdfx_waitfifo call:" + " %.2f\n", + tdev->fifo_waitcycles/(float)(tdev->waitfifo_calls) ); + D_DEBUG( "DirectFB/TDFX: Average fifo space cache hits: %02d%%\n", + (int)(100 * tdev->fifo_cache_hits/ + (float)(tdev->waitfifo_calls)) ); + + D_DEBUG( "DirectFB/TDFX: Pixels Out: %d\n", tdrv->voodoo3D->fbiPixelsOut ); + D_DEBUG( "DirectFB/TDFX: Triangles Out: %d\n", tdrv->voodoo3D->fbiTrianglesOut ); +} + +static void +driver_close_driver( CoreGraphicsDevice *device, + void *driver_data ) +{ + TDFXDriverData *tdrv = (TDFXDriverData*) driver_data; + + dfb_gfxcard_unmap_mmio( device, tdrv->mmio_base, -1 ); +} + |