/*
 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "Xarch.h"
#include "xaalocal.h"
#include "xaarop.h"
#include "miline.h"

#include "savage_driver.h"
#include "savage_regs.h"
#include "savage_bci.h"
#include "savage_dri.h"
#include "dri.h"

/* Forward declaration of functions used in the driver */

static void SavageSetupForScreenToScreenCopy(
    ScrnInfoPtr pScrn,
    int xdir,
    int ydir,
    int rop,
    unsigned planemask,
    int transparency_color);

static void SavageSubsequentScreenToScreenCopy(
    ScrnInfoPtr pScrn,
    int x1,
    int y1,
    int x2,
    int y2,
    int w,
    int h);

static void SavageSetupForSolidFill(
    ScrnInfoPtr pScrn,
    int color,
    int rop,
    unsigned planemask);

static void SavageSubsequentSolidFillRect(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h);
#if 0
static int
SavageCheckLineparameters(int * x1,int * y1,int * x2,int * y2);
endif
static void SavageSubsequentSolidBresenhamLine(
    ScrnInfoPtr pScrn,
    int x1,
    int y1,
    int e1,
    int e2,
    int err,
    int length,
    int octant);
#if 0
  static void SavageSubsequentSolidTwoPointLine(
  ScrnInfoPtr pScrn,
  int x1,
  int y1,
  int x2,
  int y2,
  int bias);
#endif
static void SavageSubsequentSolidHorVertLine(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int len,
    int dir);
#if 0
static void SavageSetupForScreenToScreenColorExpand(
    ScrnInfoPtr pScrn,
    int bg,
    int fg,
    int rop,
    unsigned planemask);

static void SavageSubsequentScreenToScreenColorExpand(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h,
    int skipleft);
#endif

static void SavageSetupForCPUToScreenColorExpandFill(
    ScrnInfoPtr pScrn,
    int fg,
    int bg,
    int rop,
    unsigned planemask);

static void SavageSubsequentScanlineCPUToScreenColorExpandFill(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h,
    int skipleft);

static void SavageSubsequentColorExpandScanline(
    ScrnInfoPtr pScrn,
    int buffer_no);

static void SavageSetupForMono8x8PatternFill(
    ScrnInfoPtr pScrn,
    int patternx,
    int patterny,
    int fg,
    int bg,
    int rop,
    unsigned planemask);

static void SavageSubsequentMono8x8PatternFillRect(
    ScrnInfoPtr pScrn,
    int pattern0,
    int pattern1,
    int x,
    int y,
    int w,
    int h);

static void SavageSetupForColor8x8PatternFill(
    ScrnInfoPtr pScrn,
    int patternx,
    int patterny,
    int rop,
    unsigned planemask,
    int trans_col);

static void SavageSubsequentColor8x8PatternFillRect(
    ScrnInfoPtr pScrn,
    int pattern0,
    int pattern1,
    int x,
    int y,
    int w,
    int h);

static void SavageSetClippingRectangle(
    ScrnInfoPtr pScrn,
    int x1,
    int y1,
    int x2,
    int y2);

static void SavageDisableClipping( ScrnInfoPtr );

#if 0
static void SavageSubsequentSolidFillTrap(
    ScrnInfoPtr pScrn,
    int y,
    int h,
    int left,
    int dxl,
    int dyl,
    int el,
    int right,
    int dxr,
    int dyr,
    int er);
#endif

/* from savage_image.c: */

void SavageSetupForImageWrite(
    ScrnInfoPtr pScrn,
    int rop,
    unsigned int planemask,
    int transparency_color,
    int bpp,
    int depth);

void SavageSubsequentImageWriteRect(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h,
    int skipleft);

void SavageWriteBitmapCPUToScreenColorExpand (
    ScrnInfoPtr pScrn,
    int x, int y, int w, int h,
    unsigned char * src,
    int srcwidth,
    int skipleft,
    int fg, int bg,
    int rop,
    unsigned int planemask
    );

int SavageHelpSolidROP(ScrnInfoPtr, int *, int, int *);


unsigned long writedw( unsigned long addr, unsigned long value );
unsigned long readdw( unsigned long addr );
unsigned long readfb( unsigned long addr );
unsigned long writefb( unsigned long addr, unsigned long value );
void writescan( unsigned long scan, unsigned long color );

/*
 * This is used to cache the last known value for routines we want to
 * call from the debugger.
 */
ScrnInfoPtr gpScrn = 0;

/* Acceleration init function, sets up pointers to our accelerated functions */

Bool
SavageInitAccel(ScreenPtr pScreen)
{
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    SavagePtr psav = SAVPTR(pScrn);

    XAAInfoRecPtr xaaptr;
    BoxRec AvailFBArea;

    /* Set-up our GE command primitive */
  
    if (pScrn->depth == 8) {
        psav->PlaneMask = 0xFF;
    }
    else if (pScrn->depth == 15) {
        psav->PlaneMask = 0x7FFF;
    }
    else if (pScrn->depth == 16) {
        psav->PlaneMask = 0xFFFF;
    }
    else if (pScrn->depth == 24) {
        psav->PlaneMask = 0xFFFFFF;
    }

    /* General acceleration flags */

    if (!(xaaptr = psav->AccelInfoRec = XAACreateInfoRec()))
        return FALSE;

    xaaptr->Flags = 0
    	| PIXMAP_CACHE
        | OFFSCREEN_PIXMAPS
        | LINEAR_FRAMEBUFFER
        ;

    /* Clipping */

    xaaptr->SetClippingRectangle = SavageSetClippingRectangle;
    xaaptr->DisableClipping = SavageDisableClipping;
    xaaptr->ClippingFlags = 0
        | HARDWARE_CLIP_SOLID_FILL 
        | HARDWARE_CLIP_SOLID_LINE
        | HARDWARE_CLIP_DASHED_LINE
        | HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY
        | HARDWARE_CLIP_MONO_8x8_FILL
        | HARDWARE_CLIP_COLOR_8x8_FILL
        ;

    xaaptr->Sync = SavageAccelSync;


    /* ScreenToScreen copies */

#if 1
    xaaptr->SetupForScreenToScreenCopy = SavageSetupForScreenToScreenCopy;
    xaaptr->SubsequentScreenToScreenCopy = SavageSubsequentScreenToScreenCopy;
    xaaptr->ScreenToScreenCopyFlags = NO_TRANSPARENCY | NO_PLANEMASK | ROP_NEEDS_SOURCE;
#endif


    /* Solid filled rectangles */

#if 1
    xaaptr->SetupForSolidFill = SavageSetupForSolidFill;
    xaaptr->SubsequentSolidFillRect = SavageSubsequentSolidFillRect;
    xaaptr->SolidFillFlags = NO_PLANEMASK | ROP_NEEDS_SOURCE;
#endif

    /* Mono 8x8 pattern fills */

#if 1
    xaaptr->SetupForMono8x8PatternFill = SavageSetupForMono8x8PatternFill;
    xaaptr->SubsequentMono8x8PatternFillRect 
    	= SavageSubsequentMono8x8PatternFillRect;
    xaaptr->Mono8x8PatternFillFlags = 0
        | HARDWARE_PATTERN_PROGRAMMED_BITS 
        | HARDWARE_PATTERN_SCREEN_ORIGIN
	| ROP_NEEDS_SOURCE
        | BIT_ORDER_IN_BYTE_MSBFIRST
        ;
	if(psav->Chipset == S3_SAVAGE4)
        xaaptr->Mono8x8PatternFillFlags |= NO_TRANSPARENCY;
#endif

    /* Color 8x8 pattern fills */

  /*
     * With the exception of the Savage3D and Savage4, all of the Savage
     * chips require that bitmap descriptors have a stride that is a
     * multiple of 16 pixels.  This includes any descriptor used for
     * color pattern fills, which COMPLETELY screws the XAA 8x8 color 
     * pattern support.
     *
     * We could double the width ourselves into a reserved frame buffer
     * section, but since I went 18 months with only ONE report of this
     * error, it seems hardly worth the trouble.
     */

#if 1
    /*if( (psav->Chipset == S3_TWISTER)
      || (psav->Chipset == S3_SAVAGE3D)
      || (psav->Chipset == S3_SAVAGE4)) */
    {
    xaaptr->SetupForColor8x8PatternFill =
        SavageSetupForColor8x8PatternFill;
    xaaptr->SubsequentColor8x8PatternFillRect =
        SavageSubsequentColor8x8PatternFillRect;
    xaaptr->Color8x8PatternFillFlags = 0
        | NO_TRANSPARENCY
    	| HARDWARE_PATTERN_PROGRAMMED_BITS
        | HARDWARE_PATTERN_PROGRAMMED_ORIGIN
        ;
  }
 #endif

    /* Solid lines */

#if 1
    xaaptr->SolidLineFlags = NO_PLANEMASK;
    xaaptr->SetupForSolidLine = SavageSetupForSolidFill;
    xaaptr->SubsequentSolidHorVertLine = SavageSubsequentSolidHorVertLine;
#endif
    
#if 1    
    xaaptr->SubsequentSolidBresenhamLine = SavageSubsequentSolidBresenhamLine;
#if 0
    xaaptr->SubsequentSolidTwoPointLine = SavageSubsequentSolidTwoPointLine;
    xaaptr->SubsequentSolidFillTrap = SavageSubsequentSolidFillTrap; 
#endif
    xaaptr->SolidBresenhamLineErrorTermBits = 14; 
#endif

    /* ImageWrite */
#if 1 /* should this be enabled?  it is in Tim's driver */
    xaaptr->ImageWriteFlags = 0
        | NO_PLANEMASK
        | CPU_TRANSFER_PAD_DWORD
        | SCANLINE_PAD_DWORD
        | BIT_ORDER_IN_BYTE_MSBFIRST
        | LEFT_EDGE_CLIPPING
        ;
    xaaptr->SetupForImageWrite = SavageSetupForImageWrite;
    xaaptr->SubsequentImageWriteRect = SavageSubsequentImageWriteRect;
    xaaptr->NumScanlineImageWriteBuffers = 1;
    xaaptr->ImageWriteBase = psav->BciMem;
    xaaptr->ImageWriteRange = 120 * 1024;
#endif
    /* WriteBitmap color expand */

#if 0
    xaaptr->WriteBitmapFlags = NO_PLANEMASK;
    xaaptr->WriteBitmap = SavageWriteBitmapCPUToScreenColorExpand;
#endif

    /* Screen to Screen color expansion.  Not implemented. */

#if 0
    xaaptr->SetupForScreenToScreenColorExpand =
        SavageSetupForScreenToScreenColorExpand;
    xaaptr->SubsequentScreenToScreenColorExpand =
        SavageSubsequentCPUToScreenColorExpand;
#endif

    /* CPU to Screen color expansion */

    xaaptr->ScanlineCPUToScreenColorExpandFillFlags = 0
        | NO_PLANEMASK
        | CPU_TRANSFER_PAD_DWORD
        | SCANLINE_PAD_DWORD
        | BIT_ORDER_IN_BYTE_MSBFIRST
        | LEFT_EDGE_CLIPPING
        | ROP_NEEDS_SOURCE
        ;

    xaaptr->SetupForScanlineCPUToScreenColorExpandFill =
        SavageSetupForCPUToScreenColorExpandFill;
    xaaptr->SubsequentScanlineCPUToScreenColorExpandFill =
        SavageSubsequentScanlineCPUToScreenColorExpandFill;
    xaaptr->SubsequentColorExpandScanline =
         SavageSubsequentColorExpandScanline;
    
    xaaptr->ColorExpandBase = psav->BciMem;
    xaaptr->ScanlineColorExpandBuffers = &xaaptr->ColorExpandBase;
    xaaptr->NumScanlineColorExpandBuffers = 1;

    /* Set up screen parameters. */
      psav->Bpp = pScrn->bitsPerPixel / 8;
      psav->Bpl = pScrn->displayWidth * psav->Bpp;
    
    /*
     * Finally, we set up the video memory space available to the pixmap
     * cache. In this case, all memory from the end of the virtual screen
     * to the end of the command overflow buffer can be used. If you haven't
     * enabled the PIXMAP_CACHE flag, then these lines can be omitted.
     */
#ifdef XF86DRI
    if (psav->directRenderingEnabled) {
        SAVAGEDRIServerPrivatePtr pSAVAGEDRIServer = psav->DRIServerInfo;
        BoxRec MemBox;
        int cpp = pScrn->bitsPerPixel / 8;
        /*int widthBytes = pScrn->displayWidth * cpp;*/
        int widthBytes = psav->lDelta;
        int bufferSize = ((pScrn->virtualY * widthBytes + SAVAGE_BUFFER_ALIGN)
                          & ~SAVAGE_BUFFER_ALIGN);
        int tiledwidthBytes,tiledBufferSize;

        pSAVAGEDRIServer->frontbufferSize = bufferSize;
        tiledwidthBytes = psav->lDelta;
        
        if (cpp == 2) {
            tiledBufferSize = ((pScrn->virtualX+63)/64)*((pScrn->virtualY+15)/16)
                *2048;
        } else {
            tiledBufferSize = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16)
                *2048;
        }
        /*set Depth buffer to 32bpp*/
        /*tiledwidthBytes_Z = ((pScrn->virtualX + 31)& ~0x0000001F)*4;
          tiledBufferSize_Z = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16)
          *2048;*/

        pSAVAGEDRIServer->backbufferSize = tiledBufferSize;
        /*pSAVAGEDRIServer->depthbufferSize = tiledBufferSize_Z;*/
        pSAVAGEDRIServer->depthbufferSize = tiledBufferSize;

        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
                   "virtualX:%d,virtualY:%d\n",
                   pScrn->virtualX,pScrn->virtualY);
        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "bpp:%d,tiledwidthBytes:%d,tiledBufferSize:%d \n",
                    pScrn->bitsPerPixel,
                    tiledwidthBytes,tiledBufferSize);

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "bpp:%d,widthBytes:%d,BufferSize:%d \n",
                    pScrn->bitsPerPixel,
                    widthBytes,bufferSize);

        pSAVAGEDRIServer->frontOffset = 0;
        pSAVAGEDRIServer->frontPitch = widthBytes;

        /* Try for front, back, depth, and two framebuffers worth of
         * pixmap cache.  Should be enough for a fullscreen background
         * image plus some leftovers.
         */
        /*     pSAVAGEDRIServer->textureSize = psav->videoRambytes -
               tiledBufferSize -
               tiledBufferSize_Z -
               -0x602000;*/
        pSAVAGEDRIServer->textureSize = psav->videoRambytes -
            4096 - /* hw cursor*/
            psav->cobSize - /*COB*/
            bufferSize-
            tiledBufferSize -
            tiledBufferSize -
            0x200000;

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "videoRambytes:0x%08lx \n",
                    psav->videoRambytes);

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "textureSize:0x%08lx \n",
                    pSAVAGEDRIServer->textureSize);

        /* If that gives us less than half the available memory, let's
         * be greedy and grab some more.  Sorry, I care more about 3D
         * performance than playing nicely, and you'll get around a full
         * framebuffer's worth of pixmap cache anyway.
         */
#if 0
        if ( pSAVAGEDRIServer->textureSize < (int)psav->FbMapSize / 2 ) {
            pSAVAGEDRIServer->textureSize = psav->FbMapSize - 4 * bufferSize;
        }
#endif
        /* Check to see if there is more room available after the maximum
         * scanline for textures.
         */
#if 0
        if ( (int)psav->FbMapSize - maxlines * widthBytes - bufferSize * 2
             > pSAVAGEDRIServer->textureSize ) {
            pSAVAGEDRIServer->textureSize = (psav->FbMapSize -
                                             maxlines * widthBytes -
                                             bufferSize * 2);
        }
#endif
        /* Set a minimum usable local texture heap size.  This will fit
         * two 256x256x32bpp textures.
         */
        if ( pSAVAGEDRIServer->textureSize < 512 * 1024 ) {
            pSAVAGEDRIServer->textureOffset = 0;
            pSAVAGEDRIServer->textureSize = 0;
        }

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "textureSize:0x%08lx \n",
                    pSAVAGEDRIServer->textureSize);

        /* Reserve space for textures */
        /*       if (pSAVAGEDRIServer->textureSize)*/
        pSAVAGEDRIServer->textureOffset = (psav->videoRambytes -
                                           4096 - /* hw cursor*/
                                           psav->cobSize - /*COB*/
                                           pSAVAGEDRIServer->textureSize) & ~SAVAGE_BUFFER_ALIGN;

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "textureOffset:0x%08lx \n",
                    pSAVAGEDRIServer->textureOffset);

        /* Reserve space for the shared depth buffer */
        /*pSAVAGEDRIServer->depthOffset = (pSAVAGEDRIServer->textureOffset -
          tiledBufferSize_Z + SAVAGE_BUFFER_ALIGN) &  ~SAVAGE_BUFFER_ALIGN;
        */
        pSAVAGEDRIServer->depthOffset = (pSAVAGEDRIServer->textureOffset -
                                         tiledBufferSize) & ~SAVAGE_BUFFER_ALIGN;
        /*pSAVAGEDRIServer->depthPitch = tiledwidthBytes_Z;*/
        pSAVAGEDRIServer->depthPitch = tiledwidthBytes;

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "depthOffset:0x%08lx,depthPicth:%d\n",
                    pSAVAGEDRIServer->depthOffset,pSAVAGEDRIServer->depthPitch);

        /* Reserve space for the shared back buffer */
        pSAVAGEDRIServer->backOffset = (pSAVAGEDRIServer->depthOffset -
                                        tiledBufferSize ) & ~SAVAGE_BUFFER_ALIGN;

        pSAVAGEDRIServer->backPitch = tiledwidthBytes;

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "backOffset:0x%08lx,backPicth:%d\n",
                    pSAVAGEDRIServer->backOffset,pSAVAGEDRIServer->backPitch);

        /*scanlines = pSAVAGEDRIServer->backOffset / widthBytes - 1;*/
        /*if ( scanlines > maxlines ) scanlines = maxlines;*/
        /* CR47983, XvMC do not work on system with frame buffer less than 32MB.
         * VBE reports frame buffer size a little less than 16MB, this makes the condition
         *   truns out FALSE.
         * Now just reduce the level to 14.5MB, things should be OK, while the hwmc frame buffer layout
         *    caculation need more understanding and should be fixed.
         */
        /*if total memory is less than 16M, there is no HWMC support */
        if(psav->videoRambytes < /*16*/(14*1024+512)*1024L)
        {
            psav->hwmcOffset = 0;
            psav->hwmcSize = 0;
        }
        else
        {
            psav->hwmcSize = (10*1024+512)*1024;  /* HWMC needs 10MB FB */
            psav->hwmcOffset = (psav->videoRambytes - 0x2000 - psav->hwmcSize) & 
                ~SAVAGE_BUFFER_ALIGN; 
            if (psav->hwmcOffset < bufferSize) {
                /* If hwmc buffer will lay in on-screen buffer. */
                psav->hwmcSize = 0;
                psav->hwmcOffset = 0;
            }
        }

        /* CR48438: Title: "Lots of garbage appear on the background when 
         *  drag the DVD player XINE window at 1024x768 or higher mode."
         * hwmc used xserver's memory, now xserver will get less memory.
         * Both 3D and hwmc's memory usage are considered now.
         */  
        if (pSAVAGEDRIServer->backOffset < psav->hwmcOffset )
            psav->cyMemory = pSAVAGEDRIServer->backOffset / widthBytes - 1;
        else
            psav->cyMemory = psav->hwmcOffset / widthBytes -1;
        if (psav->cyMemory > 0x7FFF) {
            psav->cyMemory = 0x7FFF;
        }

        MemBox.x1 = 0;
        MemBox.y1 = 0;
        MemBox.x2 = psav->cxMemory;
        MemBox.y2 = psav->cyMemory;
        
        if (!xf86InitFBManager(pScreen, &MemBox)) {
            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                       "Memory manager initialization to (%d,%d) (%d,%d) failed\n",
                       MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2 );
            return FALSE;
        } else {
            int tmp,width, height;
            
            xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                        "Memory manager initialized to (%d,%d) (%d,%d)\n",
                        MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2 );
            /*
             * because the alignment requirement,the on-screen need more memory
             * than (0,0,virtualX,virtualY), but xf86InitFBManager only subtract
             * (pScrn->virtualX * pScrn->virtualY from (0,0,cxMemory,cyMemory),so
             * here,we should reserver some memory for on-screen
             */
            tmp = ((psav->cxMemory * pScrn->virtualY - pScrn->virtualX * pScrn->virtualY)
                   + psav->cxMemory -1) / (psav->cxMemory);
            if (tmp)
                xf86AllocateOffscreenArea(pScreen, psav->cxMemory,tmp, 0, NULL, NULL, NULL);
            
            if (xf86QueryLargestOffscreenArea(pScreen, &width,
                                              &height, 0, 0, 0 ) ) {
                xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                            "Largest offscreen area available: %d x %d\n",
                            width, height );
            }
        }
        psav->reserved = 0;

        if(tiledBufferSize > bufferSize)
        {
            psav->reserved = xf86AllocateOffscreenLinear(pScreen,
                                                         (tiledBufferSize - bufferSize),1,0,0,0);

        }
        if(psav->reserved)
            xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                        "Reserved for tiled front buffer at offset 0x%08lx ,size:0x%08lx\n",
                        psav->reserved->offset, psav->reserved->size);

        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "Reserved back buffer at offset 0x%x\n",
                    pSAVAGEDRIServer->backOffset );
        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "Reserved depth buffer at offset 0x%x\n",
                    pSAVAGEDRIServer->depthOffset );
        xf86DrvMsg( pScrn->scrnIndex, X_INFO,
                    "Reserved %d kb for textures at offset 0x%x\n",
                    pSAVAGEDRIServer->textureSize/1024,
                    pSAVAGEDRIServer->textureOffset );
    }
    else
#endif
    {
        int tmp;

        /*
         * why this code? because BoxRec members are  short int
         * if cyMemory is bigger than 0x7fff,then it will overflow
         */
        if (psav->cyMemory > 0x7FFF) {
            psav->cyMemory = 0x7FFF;
        }
            
        AvailFBArea.x1 = 0;
        AvailFBArea.y1 = 0;
        AvailFBArea.x2 = psav->cxMemory;
        AvailFBArea.y2 = psav->cyMemory;
        xf86InitFBManager(pScreen, &AvailFBArea);
        /*
         * because the alignment requirement,the on-screen need more memory
         * than (0,0,virtualX,virtualY), but xf86InitFBManager only subtract
         * (pScrn->virtualX * pScrn->virtualY from (0,0,cxMemory,cyMemory),so
         * here,we should reserver some memory for on-screen
         */
        tmp = ((psav->cxMemory * pScrn->virtualY - pScrn->virtualX * pScrn->virtualY)
               + psav->cxMemory -1) / (psav->cxMemory);
        if (tmp)
            xf86AllocateOffscreenArea(pScreen, psav->cxMemory,tmp, 0, NULL, NULL, NULL);
        
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
                   "Using %d lines for offscreen memory.\n",
                   psav->cyMemory - pScrn->virtualY );
    }
    return XAAInit(pScreen, xaaptr);
}




/* The sync function for the GE */
void
SavageAccelSync(ScrnInfoPtr pScrn)
{
    SavagePtr psav = SAVPTR(pScrn);
    psav->WaitIdleEmpty(psav);
}


/*
 * The XAA ROP helper routines all assume that a solid color is a 
 * "pattern".  The Savage chips, however, apply a non-stippled solid
 * color as "source".  Thus, we use a slightly customized version.
 */

static int
SavageHelpPatternROP(ScrnInfoPtr pScrn, int *fg, int *bg, int pm, int *rop)
{
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    int ret = 0;
    
    pm &= infoRec->FullPlanemask;

    if(pm == infoRec->FullPlanemask) {
        if(!NO_SRC_ROP(*rop)) 
            ret |= ROP_PAT;
        *rop = XAACopyROP[*rop];
    } else {	
        switch(*rop) {
            case GXnoop:
                break;
            case GXset:
            case GXclear:
            case GXinvert:
                ret |= ROP_PAT;
                *fg = pm;
                if(*bg != -1)
                    *bg = pm;
                break;
            default:
                ret |= ROP_PAT | ROP_SRC;
                break;
        }
        *rop = XAACopyROP_PM[*rop];
    }

    return ret;
}


int
SavageHelpSolidROP(ScrnInfoPtr pScrn, int *fg, int pm, int *rop)
{
    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
    int ret = 0;

    pm &= infoRec->FullPlanemask;

    if(pm == infoRec->FullPlanemask) {
        if(!NO_SRC_ROP(*rop)) 
            ret |= ROP_PAT;
        *rop = XAACopyROP[*rop];
    } else {	
        switch(*rop) {
            case GXnoop:
                break;
            case GXset:
            case GXclear:
            case GXinvert:
                ret |= ROP_PAT;
                *fg = pm;
                break;
            default:
                ret |= ROP_PAT | ROP_SRC;
                break;
        }
        *rop = XAACopyROP_PM[*rop];
    }

    return ret;
}



/* These are the ScreenToScreen bitblt functions. We support all ROPs, all
 * directions, and a planemask by adjusting the ROP and using the mono pattern
 * registers.
 *
 * (That's a lie; we don't really support planemask.)
 */

static void 
SavageSetupForScreenToScreenCopy(
    ScrnInfoPtr pScrn,
    int xdir, 
    int ydir,
    int rop,
    unsigned planemask,
    int transparency_color)
{
    SavagePtr psav = SAVPTR(pScrn);
    int cmd;

    cmd = BCI_CMD_RECT | BCI_CMD_DEST_GBD | BCI_CMD_SRC_GBD;
    BCI_CMD_SET_ROP( cmd, XAACopyROP[rop] );
    if (transparency_color != -1)
        cmd |= BCI_CMD_SEND_COLOR | BCI_CMD_SRC_TRANSPARENT;

    if (xdir == 1 ) cmd |= BCI_CMD_RECT_XP;
    if (ydir == 1 ) cmd |= BCI_CMD_RECT_YP;

    psav->SavedBciCmd = cmd;
    psav->SavedBgColor = transparency_color;
}

static void 
SavageSubsequentScreenToScreenCopy(
    ScrnInfoPtr pScrn,
    int x1,
    int y1,
    int x2,
    int y2,
    int w,
    int h)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;

    if (!w || !h) return;
    if (!(psav->SavedBciCmd & BCI_CMD_RECT_XP)) {
        w --;
        x1 += w;
        x2 += w;
        w ++;
    }
    if (!(psav->SavedBciCmd & BCI_CMD_RECT_YP)) {
        h --;
        y1 += h;
        y2 += h;
        h ++;
    }

    psav->WaitQueue(psav,6);
    BCI_SEND(psav->SavedBciCmd);
   /*    if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
          BCI_SEND(psav->SavedClipTopLeft);
          BCI_SEND(psav->SavedClipBottomRight);
          }
    */
     if (psav->SavedBgColor != -1) 
        BCI_SEND(psav->SavedBgColor);
    BCI_SEND(BCI_X_Y(x1, y1));
    BCI_SEND(BCI_X_Y(x2, y2));
    BCI_SEND(BCI_W_H(w, h));
}


/*
 * SetupForSolidFill is also called to set up for lines.
 */ 

static void 
SavageSetupForSolidFill(
    ScrnInfoPtr pScrn,
    int color, 
    int rop,
    unsigned planemask)
{
    SavagePtr psav = SAVPTR(pScrn);
    XAAInfoRecPtr xaaptr = GET_XAAINFORECPTR_FROM_SCRNINFOPTR( pScrn );
    int cmd;
    int mix;

    cmd = BCI_CMD_RECT
        | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
        | BCI_CMD_DEST_GBD | BCI_CMD_SRC_SOLID;

    /* Don't send a color if we don't have to. */

    if( rop == GXcopy )
    {
        if( color == 0 )
            rop = GXclear;
        else if( color == xaaptr->FullPlanemask )
            rop = GXset;
    }

    mix = SavageHelpSolidROP( pScrn, &color, planemask, &rop );

    if( mix & ROP_PAT )
        cmd |= BCI_CMD_SEND_COLOR;

    BCI_CMD_SET_ROP( cmd, rop );

    psav->SavedBciCmd = cmd;
    psav->SavedFgColor = color;
}
    
    
static void 
SavageSubsequentSolidFillRect(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;
    
    if( !w || !h )
        return;

    psav->WaitQueue(psav,5);

    BCI_SEND(psav->SavedBciCmd);
   /*    if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
          BCI_SEND(psav->SavedClipTopLeft);
          BCI_SEND(psav->SavedClipBottomRight);
          }*/
     if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
        BCI_SEND(psav->SavedFgColor);

    BCI_SEND(BCI_X_Y(x, y));
    BCI_SEND(BCI_W_H(w, h));
}

#if 0
static void
SavageSetupForScreenToScreenColorExpand(
    ScrnInfoPtr pScrn,
    int bg,
    int fg,
    int rop,
    unsigned planemask)
{
    /*    SavagePtr psav = SAVPTR(pScrn); */
}

static void
SavageSubsequentScreenToScreenColorExpand(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h,
    int skipleft)
{
    /*    SavagePtr psav = SAVPTR(pScrn); */
}
#endif


static void
SavageSetupForCPUToScreenColorExpandFill(
    ScrnInfoPtr pScrn,
    int fg,
    int bg,
    int rop,
    unsigned planemask)
{
    SavagePtr psav = SAVPTR(pScrn);
    int cmd;
    int mix;
    
    cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
        | BCI_CMD_CLIP_LR
        | BCI_CMD_DEST_GBD | BCI_CMD_SRC_MONO;

    mix = SavageHelpPatternROP( pScrn, &fg, &bg, planemask, &rop );

    if( mix & ROP_PAT )
        cmd |= BCI_CMD_SEND_COLOR;

    BCI_CMD_SET_ROP( cmd, rop );

    if (bg != -1)
        cmd |= BCI_CMD_SEND_COLOR;
    else 
        cmd |= BCI_CMD_SRC_TRANSPARENT;

    psav->SavedBciCmd = cmd;
    psav->SavedFgColor = fg;
    psav->SavedBgColor = bg;
}


static void
SavageSubsequentScanlineCPUToScreenColorExpandFill(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int w,
    int h,
    int skipleft)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;

    /* XAA will be sending bitmap data next.  */
    /* We should probably wait for empty/idle here. */

    psav->WaitQueue(psav,20);

    BCI_SEND(psav->SavedBciCmd);
    BCI_SEND(BCI_CLIP_LR(x+skipleft, x+w-1));
    w = (w + 31) & ~31;
    if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
        BCI_SEND(psav->SavedFgColor);
    if( psav->SavedBgColor != -1 )
        BCI_SEND(psav->SavedBgColor);
    BCI_SEND(BCI_X_Y(x, y));
    BCI_SEND(BCI_W_H(w, 1));
    
    psav->Rect.x = x;
    psav->Rect.y = y + 1;
    psav->Rect.width = w;
    psav->Rect.height = h - 1;
}

static void
SavageSubsequentColorExpandScanline(
    ScrnInfoPtr pScrn,
    int buffer_no)
{
    /* This gets call after each scanline's image data has been sent. */
    SavagePtr psav = SAVPTR(pScrn);
    xRectangle xr = psav->Rect;
    BCI_GET_PTR;

    if( xr.height )
    {
        psav->WaitQueue(psav,20);
        BCI_SEND(BCI_X_Y( xr.x, xr.y));
        BCI_SEND(BCI_W_H( xr.width, 1 ));
        psav->Rect.height--;
        psav->Rect.y++;
    }
}


/*
 * The meaning of the two pattern paremeters to Setup & Subsequent for
 * Mono8x8Patterns varies depending on the flag bits.  We specify
 * HW_PROGRAMMED_BITS, which means our hardware can handle 8x8 patterns
 * without caching in the frame buffer.  Thus, Setup gets the pattern bits.
 * There is no way with BCI to rotate an 8x8 pattern, so we do NOT specify
 * HW_PROGRAMMED_ORIGIN.  XAA wil rotate it for us and pass the rotated
 * pattern to both Setup and Subsequent.  If we DID specify PROGRAMMED_ORIGIN,
 * then Setup would get the unrotated pattern, and Subsequent gets the
 * origin values.
 */

static void
SavageSetupForMono8x8PatternFill(
    ScrnInfoPtr pScrn,
    int patternx,
    int patterny,
    int fg, 
    int bg,
    int rop,
    unsigned planemask)
{
    SavagePtr psav = SAVPTR(pScrn);
    int cmd;
    int mix;

    mix = XAAHelpPatternROP( pScrn, &fg, &bg, planemask, &rop );

    cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
        | BCI_CMD_DEST_GBD;

    if( mix & ROP_PAT )
        cmd |= BCI_CMD_SEND_COLOR | BCI_CMD_PAT_MONO;

    if (bg == -1)
        cmd |= BCI_CMD_PAT_TRANSPARENT;

    BCI_CMD_SET_ROP(cmd, rop);

    psav->SavedBciCmd = cmd;
    psav->SavedFgColor = fg;
    psav->SavedBgColor = bg;
}


static void
SavageSubsequentMono8x8PatternFillRect(
    ScrnInfoPtr pScrn,
    int pattern0,
    int pattern1,
    int x,
    int y,
    int w,
    int h)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;

    /*
     * I didn't think it was my job to do trivial rejection, but 
     * miFillGeneralPolygon definitely generates null spans, and XAA
     * just passes them through.
     */ 

    if( !w || !h)
        return;

    psav->WaitQueue(psav,7);
    BCI_SEND(psav->SavedBciCmd);
   /*    if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
          BCI_SEND(psav->SavedClipTopLeft);
          BCI_SEND(psav->SavedClipBottomRight);
          }
*/
    if( psav->SavedBciCmd & BCI_CMD_SEND_COLOR )
        BCI_SEND(psav->SavedFgColor);
    if( psav->SavedBgColor != -1 )
        BCI_SEND(psav->SavedBgColor);
    BCI_SEND(BCI_X_Y(x, y));
    BCI_SEND(BCI_W_H(w, h));
    if( psav->SavedBciCmd & BCI_CMD_PAT_MONO )
    {
        BCI_SEND(pattern0);
        BCI_SEND(pattern1);
    }
}


static void 
SavageSetupForColor8x8PatternFill(
    ScrnInfoPtr pScrn,
    int patternx,
    int patterny,
    int rop,
    unsigned planemask,
    int trans_col)
{
    SavagePtr psav = SAVPTR(pScrn);

    int cmd;
    int mix;
    unsigned int bd;
    int pat_offset;
    
    /* ViRGEs and Savages do not support transparent color patterns. */
    /* We set the NO_TRANSPARENCY bit, so we should never receive one. */

    pat_offset = (int) (patternx * psav->Bpp + patterny * psav->Bpl);

    cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP
        | BCI_CMD_DEST_GBD | BCI_CMD_PAT_SBD_COLOR_NEW;
        
    mix = XAAHelpSolidROP( pScrn, &trans_col, planemask, &rop );

    BCI_CMD_SET_ROP(cmd, rop);
    bd = BCI_BD_BW_DISABLE;
    BCI_BD_SET_BPP(bd, pScrn->bitsPerPixel);
    BCI_BD_SET_STRIDE(bd, 8);

    psav->SavedBciCmd = cmd;
    psav->SavedSbdOffset = pat_offset;
    psav->SavedSbd = bd;
    psav->SavedBgColor = trans_col;
}


static void
SavageSubsequentColor8x8PatternFillRect(
    ScrnInfoPtr pScrn,
    int patternx,
    int patterny,
    int x,
    int y,
    int w,
    int h)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;

    if( !w || !h)
        return;

    psav->WaitQueue(psav,6);
    BCI_SEND(psav->SavedBciCmd);
    BCI_SEND(psav->SavedSbdOffset);
    BCI_SEND(psav->SavedSbd);
    BCI_SEND(BCI_X_Y(patternx,patterny));
   /*    if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
          BCI_SEND(psav->SavedClipTopLeft);
          BCI_SEND(psav->SavedClipBottomRight);
          }*/
    BCI_SEND(BCI_X_Y(x, y));
    BCI_SEND(BCI_W_H(w, h));
}

#if 0
static int
SavageCheckLineparameters(int * x1,int * y1,int * x2,int * y2)
{
    float k;
    if ( *x1 < 0 && *x2 < 0 )
        return 0;
    if ( *y1<0 && *y2 <0 )
        return 0;

    k = (float)(*y2 - *y1)/(*x2 - *x1);
 
    if ( *x1 < 0 )
    {
        *y1 = *y1 - k*(*x1);
        *x1 = 0;
    }
    if ( *y1 < 0 )
    {
        *x1 = *x1-(*y1)/k;
        *y1 = 0;
    }
    if ( *x1 < 0 && *y1 < 0 )
        return 0;

    if ( *x2 < 0 )
    {
        *y2 = *y2 -k*(*x2);
        *x2 = 0;
    }
    if ( *y2 < 0 )
    {
        *x2 = *x2-(*y2)/k;
        *y2 = 0;
    }
    if ( *x2 < 0 && *y2 < 0)
        return 0;
    return 1;
}
#endif
  static void
  SavageSubsequentSolidBresenhamLine(
  ScrnInfoPtr pScrn,
  int x1,
  int y1,
  int e1,
  int e2,
  int err,
  int length,
  int octant)
  {
  SavagePtr psav = SAVPTR(pScrn);
  BCI_GET_PTR;
  int cmd;

  cmd = (psav->SavedBciCmd & 0x00ffffff);
  cmd |= BCI_CMD_LINE_LAST_PIXEL;

  #ifdef DEBUG_EXTRA
    ErrorF("BresenhamLine, (%4d,%4d), len %4d, oct %d, err %4d,%4d, %4d clr %08x\n",
        x1, y1, length, octant, e1, e2, err,psav->SavedFgColor );
  #endif

  psav->WaitQueue(psav, 5 );
  BCI_SEND(cmd);    
/*
  if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
  BCI_SEND(psav->SavedClipTopLeft);
  BCI_SEND(psav->SavedClipBottomRight);
  }
*/
  if( cmd & BCI_CMD_SEND_COLOR )
  BCI_SEND( psav->SavedFgColor );
  BCI_SEND(BCI_LINE_X_Y(x1, y1));
  BCI_SEND(BCI_LINE_STEPS(e2-e1, e2));
  BCI_SEND(BCI_LINE_MISC(length, 
  			(octant & YMAJOR),
  			!(octant & XDECREASING),
  			!(octant & YDECREASING),
  			e2+err));
  }

#if 0
  static void 
  SavageSubsequentSolidTwoPointLine(
  ScrnInfoPtr pScrn,
  int x1,
  int y1,
  int x2,
  int y2,
  int bias)
  {
  SavagePtr psav = SAVPTR(pScrn);
  BCI_GET_PTR;

  int cmd;
  int dx, dy;
  int min, max, xp, yp, ym;

  if ( S3_SAVAGE4_SERIES(psav->Chipset) || S3_SAVAGE3D_SERIES(psav->Chipset))
  if ( x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 )     
  if ( !SavageCheckLineparameters(&x1,&y1,&x2,&y2))
  return;
 
  dx = x2 - x1;
  dy = y2 - y1;

  #ifdef DEBUG_EXTRA
  ErrorF("TwoPointLine, (%4d,%4d)-(%4d,%4d), clr %08x, last pt %s\n",
  x1, y1, x2, y2, psav->SavedFgColor, (bias & 0x100)?"NO ":"YES");
  #endif
  xp = (dx >= 0);
  if( !xp ) {
  dx = -dx;
  }

  yp = (dy >= 0);
  if( !yp ) {
  dy = -dy;
  }

  ym = (dy > dx);
  if( ym ) {
  max = dy;
  min = dx;
  }
  else {
  max = dx;
  min = dy;
  }

  if( !(bias & 0x100) ) {
  max++;
  }

  cmd = (psav->SavedBciCmd & 0x00ffffff);
  cmd |= BCI_CMD_LINE_LAST_PIXEL;

  psav->WaitQueue(psav,5);
/*
  if( psav->SavedBciCmd & BCI_CMD_CLIP_NEW){
  BCI_SEND(psav->SavedClipTopLeft);
  BCI_SEND(psav->SavedClipBottomRight);
  }
*/
  BCI_SEND( cmd );
  if( cmd & BCI_CMD_SEND_COLOR )
  BCI_SEND( psav->SavedFgColor );
  BCI_SEND( BCI_LINE_X_Y( x1, y1 ) );
  BCI_SEND( BCI_LINE_STEPS( 2 * (min - max), 2 * min ) );
  BCI_SEND( BCI_LINE_MISC( max, ym, xp, yp, 2 * min - max ) );
  }
#endif
static void
SavageSubsequentSolidHorVertLine(
    ScrnInfoPtr pScrn,
    int x,
    int y,
    int len,
    int dir)
{
    if(dir == DEGREES_0)
    {
        SavageSubsequentSolidFillRect(pScrn, x, y, len, 1);
    }
    else
    {
        SavageSubsequentSolidFillRect(pScrn, x, y, 1, len);
    }

}

static void
SavageSetClippingRectangle(
    ScrnInfoPtr pScrn,
    int x1,
    int y1,
    int x2,
    int y2)
{
    SavagePtr psav = SAVPTR(pScrn);
    BCI_GET_PTR;
    int cmd;

#ifdef DEBUG_EXTRA
    ErrorF("ClipRect, (%4d,%4d)-(%4d,%4d) \n", x1, y1, x2, y2 );
#endif

    cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
	psav->WaitQueue(psav,3);
	BCI_SEND(cmd);
	BCI_SEND(BCI_CLIP_TL(y1, x1));
	BCI_SEND(BCI_CLIP_BR(y2, x2));

 /*    psav->SavedClipTopLeft = BCI_CLIP_TL(y1,x1);
          psav->SavedClipBottomRight = BCI_CLIP_BR(y2,x2);*/
      psav->SavedBciCmd |= BCI_CMD_CLIP_CURRENT;
}


static void SavageDisableClipping( ScrnInfoPtr pScrn )
{
    SavagePtr psav = SAVPTR(pScrn);
#ifdef DEBUG_EXTRA
    ErrorF("Kill ClipRect\n");
#endif
    psav->SavedBciCmd &= ~BCI_CMD_CLIP_NEW;
}


/* Trapezoid solid fills. XAA passes the coordinates of the top start
 * and end points, and the slopes of the left and right vertexes. We
 * use this info to generate the bottom points. We use a mixture of
 * floating-point and fixed point logic; the biases are done in fixed
 * point. Essentially, these were determined experimentally. The function
 * passes xtest, but I suspect that it will not match cfb for large polygons.
 *
 * This code is from the ViRGE.  We need to modify it for Savage if we ever
 * decide to turn it on.
 */

#if 0
void
SavageSubsequentSolidFillTrap(
    ScrnInfoPtr pScrn,
    int y,
    int h,
    int left,
    int dxl,
    int dyl,
    int el,
    int right,
    int dxr,
    int dyr,
    int er)
{
    int l_xdelta, r_xdelta;
    double lendx, rendx, dl_delta, dr_delta;
    int lbias, rbias;
    unsigned int cmd;
    double l_sgn = -1.0, r_sgn = -1.0;

    cmd |= (CMD_POLYFILL | CMD_AUTOEXEC | MIX_MONO_PATT) ;
    cmd |= (psav->SavedRectCmdForLine & (0xff << 17));

    l_xdelta = -(dxl << 20)/ dyl;
    r_xdelta = -(dxr << 20)/ dyr;

    dl_delta = -(double) dxl / (double) dyl;
    dr_delta = -(double) dxr / (double) dyr;
    if (dl_delta < 0.0) l_sgn = 1.0;
    if (dr_delta < 0.0) r_sgn = 1.0;

    lendx = l_sgn * ((double) el / (double) dyl) + left + ((h - 1) * dxl) / (double) dyl;
    rendx = r_sgn * ((double) er / (double) dyr) + right + ((h - 1) * dxr) / (double) dyr;

    /* We now have four cases */

    if (fabs(dl_delta) > 1.0) {  /* XMAJOR line */
        if (dxl > 0) { lbias = ((1 << 20) - h); }
        else { lbias = 0; }
    }
    else {
        if (dxl > 0) { lbias = ((1 << 20) - 1) + l_xdelta / 2; }
        else { lbias = 0; }
    }

    if (fabs(dr_delta) > 1.0) {   /* XMAJOR line */
        if (dxr > 0) { rbias = (1 << 20); }
        else { rbias = ((1 << 20) - 1); }
    }
    else {
        if (dxr > 0) { rbias = (1 << 20); }
        else { rbias = ((1 << 20) - 1); }
    }

    psav->WaitQueue(psav,8);
    CACHE_SETP_CMD_SET(cmd);
    SETP_PRDX(r_xdelta);
    SETP_PLDX(l_xdelta);
    SETP_PRXSTART(((int) (rendx * (double) (1 << 20))) + rbias);
    SETP_PLXSTART(((int) (lendx * (double) (1 << 20))) + lbias);

    SETP_PYSTART(y + h - 1);
    SETP_PYCNT((h) | 0x30000000);

    CACHE_SETB_CMD_SET(psav->SavedRectCmdForLine);

}
#endif


/* Routines for debugging. */
unsigned long
writedw( unsigned long addr, unsigned long value )
{
    SavagePtr psav = SAVPTR(gpScrn);
    OUTREG32( addr, value );
    return INREG32( addr );
}

unsigned long
readdw( unsigned long addr )
{
    SavagePtr psav = SAVPTR(gpScrn);
    return INREG32( addr );
}

unsigned long
readfb( unsigned long addr )
{
    SavagePtr psav = SAVPTR(gpScrn);
    char * videobuffer = (char *) psav->FBBase;
    return *(volatile unsigned long*)(videobuffer + (addr & ~3) );
}

unsigned long
writefb( unsigned long addr, unsigned long value )
{
    SavagePtr psav = SAVPTR(gpScrn);
    char * videobuffer = (char *) psav->FBBase;
    *(unsigned long*)(videobuffer + (addr & ~3)) = value;
    return *(volatile unsigned long*)(videobuffer + (addr & ~3) );
}

void
writescan( unsigned long scan, unsigned long color )
{
    SavagePtr psav = SAVPTR(gpScrn);
    int i;
    char * videobuffer = (char *)psav->FBBase;
    videobuffer += scan * gpScrn->displayWidth * gpScrn->bitsPerPixel >> 3;
    for( i = gpScrn->displayWidth; --i; ) {
        switch( gpScrn->bitsPerPixel ) {
            case 8: 
                *videobuffer++ = color; 
                break;
            case 16: 
                *(CARD16 *)videobuffer = color;
                videobuffer += 2;
                break;
            case 32:
                *(CARD32 *)videobuffer = color;
                videobuffer += 4;
                break;
        }
    }
}

