Edit

IABSD.fr/xenocara/driver/xf86-video-apm/src/apm_funcs.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2012-05-13 20:03:52
    Hash : 210cce10
    Message : Update xf86-video-apm to 1.2.4

  • driver/xf86-video-apm/src/apm_funcs.c
  • #ifdef HAVE_CONFIG_H
    #include "config.h"
    #endif
    
    #define FASTER
    #ifndef PSZ
    #define PSZ	8
    #endif
    
    #if PSZ == 24
    #  define APM_SUFF_24	"24"
    #  define A(s)		Apm##s##24
    #else
    #  define APM_SUFF_24	""
    #  define A(s)		Apm##s
    #endif
    #define	DPRINTNAME(s)	do { xf86DrvMsgVerb(pScrn->pScreen->myNum, X_NOTICE, 6, "Apm" #s APM_SUFF_24 "\n"); } while (0)
    
    #if PSZ == 24
    #undef SETSOURCEXY
    #undef SETDESTXY
    #undef SETWIDTH
    #undef SETWIDTHHEIGHT
    #undef UPDATEDEST
    #define SETSOURCEXY(x,y)	do { int off = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0x3FFF)) * 3); SETSOURCEOFF(((off & 0xFFF000) << 4) | (off & 0xFFF)); break;} while(1)
    #define SETDESTXY(x,y)	do { int off = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0x3FFF)) * 3); SETDESTOFF(((off & 0xFFF000) << 4) | (off & 0xFFF)); break;} while(1)
    #define SETWIDTH(w)		WRXW(0x58, ((w) & 0x3FFF) * 3)
    #define SETWIDTHHEIGHT(w,h)	WRXL(0x58, ((h) << 16) | (((w) & 0x3FFF) * 3))
    #define UPDATEDEST(x,y)		(void)(curr32[0x54 / 4] = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0xFFFF)) * 3))
    #endif
    
    /* Defines */
    #define MAXLOOP 1000000
    
    
    /* Local functions */
    static void A(Sync)(ScrnInfoPtr pScrn);
    static void A(SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop,
    					unsigned int planemask);
    static void A(SubsequentSolidFillRect)(ScrnInfoPtr pScrn, int x, int y,
    				       int w, int h);
    static void A(SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir,
    					  int rop, unsigned int planemask,
                                              int transparency_color);
    static void A(SubsequentScreenToScreenCopy)(ScrnInfoPtr pScrn, int x1, int y1,
    					    int x2, int y2, int w, int h);
    #if PSZ != 24
    static void A(Sync6422)(ScrnInfoPtr pScrn);
    static void A(WriteBitmap)(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);
    static void A(TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
    				int skipleft, int startline, 
    				unsigned int **glyphs, int glyphWidth,
    				int fg, int bg, int rop, unsigned planemask);
    static void A(SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty,
    				          int fg, int bg, int rop,
    				          unsigned int planemask);
    static void A(SubsequentMono8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
    					        int paty, int x, int y,
    					        int w, int h);
    #if 0
    static void A(SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int bg, int fg, int rop, unsigned int planemask);
    static void A(SubsequentCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y, int w, int h, int skipleft);
    #endif
    static void A(SetupForScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn,
    						     int fg, int bg, int rop,
    						     unsigned int planemask);
    static void A(SetupForImageWrite)(ScrnInfoPtr pScrn, int rop,
    				  unsigned int planemask, int trans_color,
    				  int bpp, int depth);
    static void A(SubsequentImageWriteRect)(ScrnInfoPtr pScrn, int x, int y,
    					int w, int h, int skipleft);
    static void A(SubsequentScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn,
    						       int x, int y,
    						       int w, int h,
    						       int srcx, int srcy,
    						       int offset);
    static void A(SubsequentSolidBresenhamLine)(ScrnInfoPtr pScrn, int x1, int y1, int octant, int err, int e1, int e2, int length);
    static void A(SubsequentSolidBresenhamLine6422)(ScrnInfoPtr pScrn, int x1, int y1, int octant, int err, int e1, int e2, int length);
    static void A(SetClippingRectangle)(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2);
    static void A(WritePixmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
    			   unsigned char *src, int srcwidth, int rop,
    			   unsigned int planemask, int trans, int bpp,
    			   int depth);
    static void A(FillImageWriteRects)(ScrnInfoPtr pScrn, int rop,
    				    unsigned int planemask,
    				    int nBox, BoxPtr pBox, int xorg, int yorg,
    				    PixmapPtr pPix);
    static void A(SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn,int patx,int paty,
    				           int rop, unsigned int planemask,
    					   int transparency_color);
    static void A(SubsequentColor8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
    					         int paty, int x, int y,
    					         int w, int h);
    #endif
    
    /* Inline functions */
    static __inline__ void
    A(WaitForFifo)(ApmPtr pApm, int slots)
    {
      if (!pApm->UsePCIRetry) {
        volatile int i;
    
        for(i = 0; i < MAXLOOP; i++) {
          if ((STATUS() & STATUS_FIFO) >= slots)
    	break;
        }
        if (i == MAXLOOP) {
          unsigned int status = STATUS();
    
          WRXB(0x1FF, 0);
          if (!xf86ServerIsExiting())
    	  FatalError("Hung in WaitForFifo() (Status = 0x%08X)\n", status);
        }
      }
    }
    
    
    static void
    A(SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop,
    			unsigned int planemask)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SetupForSolidFill);
    #ifdef FASTER
      A(WaitForFifo)(pApm, 3 + pApm->apmClip);
      SETDEC(DEC_QUICKSTART_ONDIMX | DEC_OP_RECT | DEC_DEST_UPD_TRCORNER |
    	  pApm->CurrentLayout.Setup_DEC);
    #else
      A(WaitForFifo)(pApm, 2 + pApm->apmClip);
    #endif
    #if PSZ == 2
      pApm->color = ((color & 0xFF0000) << 8) | ((color & 0xFF0000) >> 16) |
    		  ((color & 0xFF00) << 8) | ((color & 0xFF) << 16);
    #else
      SETFOREGROUNDCOLOR(color);
    #endif
    
      if (pApm->apmClip)  {
        SETCLIP_CTRL(0);
        pApm->apmClip = FALSE;
      }
    
      SETROP(apmROP[rop]);
    }
    
    static void
    A(SubsequentSolidFillRect)(ScrnInfoPtr pScrn, int x, int y, int w, int h)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SubsequentSolidFillRect);
    #if PSZ == 24
    #  ifndef FASTER
      A(WaitForFifo)(pApm, 5);
    #  else
      A(WaitForFifo)(pApm, 4);
    #  endif
      SETOFFSET(3*(pApm->CurrentLayout.displayWidth - w));
    #if 0
      switch ((((y * pApm->CurrentLayout.displayWidth + x)* 3) / 8) % 3) {
      case 0:
          SETFOREGROUNDCOLOR(pApm->color);
          break;
      case 1:
          SETFOREGROUNDCOLOR((pApm->color << 8) | (pApm->color >> 16));
          break;
      case 2:
          SETFOREGROUNDCOLOR(pApm->color >> 8);
          break;
      }
    #endif
    #else
    #  ifndef FASTER
      A(WaitForFifo)(pApm, 3);
    #  else
      A(WaitForFifo)(pApm, 2);
    #  endif
    #endif
      SETDESTXY(x, y);
      SETWIDTHHEIGHT(w, h);
      UPDATEDEST(x + w + 1, y);
    #ifndef FASTER
      SETDEC(DEC_START | DEC_OP_RECT | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC);
    #endif
    }
    
    static void
    A(SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir, int rop,
    				unsigned int planemask, int transparency_color)
    {
      unsigned char tmp;
    
      APMDECL(pScrn);
    
      DPRINTNAME(SetupForScreenToScreenCopy);
    
      if (pApm->apmLock) {
        /*
         * This is just an attempt, because Daryll is tampering with MY registers.
         */
        tmp = (RDXB(0xDB) & 0xF4) |  0x0A;
        WRXB(0xDB, tmp);
        ApmWriteSeq(0x1B, 0x20);
        ApmWriteSeq(0x1C, 0x2F);
        pApm->apmLock = FALSE;
      }
    
      pApm->blitxdir = xdir;
      pApm->blitydir = ydir;
    
      pApm->apmTransparency = (transparency_color != -1);
    
    #ifdef FASTER
      A(WaitForFifo)(pApm, 2 + (transparency_color != -1));
      SETDEC(DEC_QUICKSTART_ONDIMX | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
    	  (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) | pApm->CurrentLayout.Setup_DEC |
    	  ((xdir < 0) ? DEC_DIR_X_NEG : DEC_DIR_X_POS) |
    	  ((ydir < 0) ? DEC_DIR_Y_NEG : DEC_DIR_Y_POS));
    #else
      A(WaitForFifo)(pApm, 1 + (transparency_color != -1));
    #endif
    
      if (transparency_color != -1)
        SETBACKGROUNDCOLOR(transparency_color);
    
      SETROP(apmROP[rop]);
    }
    
    static void
    A(SubsequentScreenToScreenCopy)(ScrnInfoPtr pScrn, int x1, int y1,
    				    int x2, int y2, int w, int h)
    {
      APMDECL(pScrn);
    #ifndef FASTER
      u32		c = pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0;
    #endif
      u32		sx, dx, sy, dy;
      int		i = y1 / pApm->CurrentLayout.Scanlines;
    
      DPRINTNAME(SubsequentScreenToScreenCopy);
      if (i && pApm->pixelStride) {
    #ifdef FASTER
        A(WaitForFifo)(pApm, 1);
        SETDEC(curr32[0x40 / 4] | (DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR));
    #else
        c |= DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG;
    #endif
        pApm->apmClip = TRUE;
        A(WaitForFifo)(pApm, 3);
        SETCLIP_LEFTTOP(x2, y2);
        SETCLIP_RIGHTBOT(x2 + w - 1, y2 + h - 1);
        SETCLIP_CTRL(1);
        w = (pApm->pixelStride * 8) / pApm->CurrentLayout.bitsPerPixel;
      }
      else {
    #ifdef FASTER
        A(WaitForFifo)(pApm, 1 + pApm->apmClip);
        SETDEC(curr32[0x40 / 4] & ~(DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR));
        if (pApm->apmClip)
    	SETCLIP_CTRL(0);
        pApm->apmClip = FALSE;
    #else
        if (pApm->apmClip) {
    	A(WaitForFifo)(pApm, 1);
    	SETCLIP_CTRL(0);
    	pApm->apmClip = FALSE;
        }
    #endif
      }
      if (i) {
          if (pApm->pixelStride) {
    	  x1 += (((y1 % pApm->CurrentLayout.Scanlines) - pApm->RushY[i - 1]) * pApm->pixelStride * 8) / pApm->CurrentLayout.bitsPerPixel;
    	  y1 = pApm->RushY[i - 1];
          }
          else
    	  y1 -= i * pApm->CurrentLayout.Scanlines;
      }
      if (pApm->blitxdir < 0)
      {
    #ifndef FASTER
        c |= DEC_DIR_X_NEG;
    #endif
        sx = x1+w-1;
        dx = x2+w-1;
      }
      else
      {
    #ifndef FASTER
        c |= DEC_DIR_X_POS;
    #endif
        sx = x1;
        dx = x2;
      }
    
      if (pApm->blitydir < 0)
      {
    #ifndef FASTER
        c |= DEC_DIR_Y_NEG | DEC_START | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
    	    pApm->CurrentLayout.Setup_DEC;
    #endif
        sy = y1+h-1;
        dy = y2+h-1;
      }
      else
      {
    #ifndef FASTER
        c |= DEC_DIR_Y_POS | DEC_START | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
    	    pApm->CurrentLayout.Setup_DEC;
    #endif
        sy = y1;
        dy = y2;
      }
    
    #if PSZ == 24
    #  ifndef FASTER
      A(WaitForFifo)(pApm, 5);
    #  else
      A(WaitForFifo)(pApm, 4);
    #  endif
      if (pApm->blitxdir == pApm->blitydir)
        SETOFFSET(3 * (pApm->CurrentLayout.displayWidth - w));
      else
        SETOFFSET(3 * (pApm->CurrentLayout.displayWidth + w));
    #else
    #  ifndef FASTER
      A(WaitForFifo)(pApm, 4);
    #  else
      A(WaitForFifo)(pApm, 3);
    #  endif
    #endif
    
      if (i && pApm->pixelStride) {
        register unsigned int off = sx + sy * pApm->CurrentLayout.displayWidth;
    
        SETSOURCEOFF(((off & 0xFFF000) << 4) | (off & 0xFFF));
      }
      else
        SETSOURCEXY(sx,sy);
      SETDESTXY(dx,dy);
      SETWIDTHHEIGHT(w,h);
      UPDATEDEST(dx + (w + 1)*pApm->blitxdir, dy);
    
    #ifndef FASTER
      SETDEC(c);
    #endif
      if (i) A(Sync)(pScrn);	/* Only for AT3D */
    }
    
    
    #if PSZ != 24
    static void
    A(SetupForScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, int bg,
    					 int rop, unsigned int planemask)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SetupForScreenToScreenColorExpandFill);
      A(WaitForFifo)(pApm, 3 + pApm->apmClip);
      if (bg == -1)
      {
        SETFOREGROUNDCOLOR(fg);
        SETBACKGROUNDCOLOR(fg+1);
        pApm->apmTransparency = TRUE;
      }
      else
      {
        SETFOREGROUNDCOLOR(fg);
        SETBACKGROUNDCOLOR(bg);
        pApm->apmTransparency = FALSE;
      }
    
      SETROP(apmROP[rop]);
    }
    
    static void
    A(WriteBitmap)(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)
    {
        APMDECL(pScrn);
        Bool	beCareful, apmClip = FALSE;
        int		wc, n, nc, wr, wrd;
        CARD32	*dstPtr;
    #ifndef FASTER
        int		c;
    #endif
    
        DPRINTNAME(WriteBitmap);
    
        if (w <= 0 && h <= 0)
    	return;
    
        /*
         * The function is a bit long, but the spirit is simple : put the monochrome
         * data in scratch memory and color-expand it using the
         * ScreenToScreenColorExpand techniques.
         */
    
        w += skipleft;
        x -= skipleft;
        wc = pApm->ScratchMemSize * 8;
        wrd = (w + 31) >> 5;
        wr = wrd << 5;
        nc = wc / wr;
        if (nc > h)
    	nc = h;
        if (wr / 8 > srcwidth)
    	beCareful = TRUE;
        else
    	beCareful = FALSE;
        srcwidth -= wr / 8;
    
        if (skipleft || w != wr) {
    	apmClip = TRUE;
    	A(WaitForFifo)(pApm, 3);
    	SETCLIP_LEFTTOP(x + skipleft, y);
    	SETCLIP_RIGHTBOT(x + w - 1, y + h - 1);
    	SETCLIP_CTRL(1);
        }
        else if (pApm->apmClip) {
    	A(WaitForFifo)(pApm, 1);
    	SETCLIP_CTRL(0);
        }
        pApm->apmClip = FALSE;
    
        A(SetupForScreenToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask);
    #ifdef FASTER
        A(WaitForFifo)(pApm, 2);
        if (pApm->apmTransparency)
        SETDEC(DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
            DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
            DEC_SOURCE_CONTIG | DEC_SOURCE_TRANSPARENCY | pApm->CurrentLayout.Setup_DEC);
        else
        SETDEC(DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
            DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
            DEC_SOURCE_CONTIG | pApm->CurrentLayout.Setup_DEC);
    #else
        A(WaitForFifo)(pApm, 1);
        c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
            DEC_START | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
            DEC_SOURCE_CONTIG | pApm->CurrentLayout.Setup_DEC;
        if (pApm->apmTransparency)
          c |= DEC_SOURCE_TRANSPARENCY;
    #endif
    
        SETDESTXY(x, y);
    
        if (!beCareful || h % nc > 3 || (w > 16 && h % nc)) {
    #ifndef FASTER
    	if (h / nc)
    	    SETWIDTHHEIGHT(wr, nc);
    #endif
    	for (n = h / nc; n-- > 0; ) {
    	    int i, j;
    
    	    if (pApm->ScratchMemPtr + nc * wrd * 4 < pApm->ScratchMemEnd) {
    #define		d	((memType)dstPtr - (memType)pApm->FbBase)
    		A(WaitForFifo)(pApm, 1);
    		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
    		switch(pApm->CurrentLayout.bitsPerPixel) {
    		case 8: case 24:
    		    SETSOURCEOFF((d & 0xFFF000) << 4 |
    				(d & 0xFFF));
    		    break;
    		case 16:
    		    SETSOURCEOFF((d & 0xFFE000) << 3 |
    				((d & 0x1FFE) >> 1));
    		    break;
    		case 32:
    		    SETSOURCEOFF((d & 0xFFC000) << 2 |
    				((d & 0x3FFC) >> 2));
    		    break;
    		}
    #undef		d
    	    }
    	    else {
    		(*pApm->AccelInfoRec->Sync)(pScrn);
    		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
    		SETSOURCEOFF(pApm->ScratchMem);
    	    }
    	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * nc) + 4) 
    	      & ~(memType)7;
    	    for (i = nc; i-- > 0; ) {
    		for (j = wrd; j-- > 0; ) {
    		    *dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
    		    src += 4;
    		}
    		src += srcwidth;
    	    }
    	    A(WaitForFifo)(pApm, 1);
    #ifdef FASTER
    	    SETWIDTHHEIGHT(wr, nc);
    #else
    	    SETDEC(c);
    #endif
    	}
        }
        else {
    #ifndef FASTER
    	if (h / nc)
    	    SETWIDTHHEIGHT(wr, nc);
    #endif
    	for (n = h / nc; n-- > 0; ) {
    	    int i, j;
    
    	    if (pApm->ScratchMemPtr + nc * wrd * 4 < pApm->ScratchMemEnd) {
    #define		d	((memType)dstPtr - (memType)pApm->FbBase)
    		A(WaitForFifo)(pApm, 1);
    		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
    		switch(pApm->CurrentLayout.bitsPerPixel) {
    		case 8: case 24:
    		    SETSOURCEOFF((d & 0xFFF000) << 4 |
    				(d & 0xFFF));
    		    break;
    		case 16:
    		    SETSOURCEOFF((d & 0xFFE000) << 3 |
    				((d & 0x1FFE) >> 1));
    		    break;
    		case 32:
    		    SETSOURCEOFF((d & 0xFFC000) << 2 |
    				((d & 0x3FFC) >> 2));
    		    break;
    		}
    #undef		d
    	    }
    	    else {
    		(*pApm->AccelInfoRec->Sync)(pScrn);
    		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
    		SETSOURCEOFF(pApm->ScratchMem);
    	    }
    	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * nc * 4) + 4) & ~7;
    	    for (i = nc; i-- > 0; ) {
    		for (j = wrd; j-- > 0; ) {
    		    if (i || j || n)
    			*dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
    		    else if (srcwidth > -8) {
    			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[2]];
    			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[1]];
    			((CARD8 *)dstPtr)[2] = byte_reversed[((CARD8 *)src)[0]];
    			dstPtr = (CARD32 *)(3 + (CARD8 *)dstPtr);
    		    }
    		    else if (srcwidth > -16) {
    			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[1]];
    			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[0]];
    			dstPtr = (CARD32 *)(2 + (CARD8 *)dstPtr);
    		    }
    		    else {
    			*(CARD8 *)dstPtr = byte_reversed[*(CARD8 *)src];
    			dstPtr = (CARD32 *)(1 + (CARD8 *)dstPtr);
    		    }
    		    src += 4;
    		}
    		src += srcwidth;
    	    }
    	    A(WaitForFifo)(pApm, 1);
    #ifdef FASTER
    	    SETWIDTHHEIGHT(wr, nc);
    #else
    	    SETDEC(c);
    #endif
    	}
        }
    
        /*
         * Same thing for the remnant
         */
        UPDATEDEST(x, y + h + 1);
        h %= nc;
        if (h) {
    	if (!beCareful) {
    	    int i, j;
    
    #ifndef FASTER
    	    SETWIDTHHEIGHT(wr, h);
    #endif
    	    if (pApm->ScratchMemPtr + h * wrd * 4 < pApm->ScratchMemEnd) {
    #define		d	((memType)dstPtr - (memType)pApm->FbBase)
    		A(WaitForFifo)(pApm, 1);
    		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
    		switch(pApm->CurrentLayout.bitsPerPixel) {
    		case 8: case 24:
    		    SETSOURCEOFF((d & 0xFFF000) << 4 |
    				(d & 0xFFF));
    		    break;
    		case 16:
    		    SETSOURCEOFF((d & 0xFFE000) << 3 |
    				((d & 0x1FFE) >> 1));
    		    break;
    		case 32:
    		    SETSOURCEOFF((d & 0xFFC000) << 2 |
    				((d & 0x3FFC) >> 2));
    		    break;
    		}
    #undef		d
    	    }
    	    else {
    		(*pApm->AccelInfoRec->Sync)(pScrn);
    		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
    		SETSOURCEOFF(pApm->ScratchMem);
    	    }
    	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * h) + 4) & ~7;
    	    for (i = h; i-- > 0; ) {
    		for (j = wrd; j-- > 0; ) {
    		    *dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
    		    src += 4;
    		}
    		src += srcwidth;
    	    }
    	    A(WaitForFifo)(pApm, 1);
    #ifdef FASTER
    	    SETWIDTHHEIGHT(wr, h);
    #else
    	    SETDEC(c);
    #endif
    	}
    	else {
    	    int i, j;
    
    #ifndef FASTER
    	    SETWIDTHHEIGHT(w, h);
    #endif
    	    if (pApm->ScratchMemPtr + h * wrd * 4 < pApm->ScratchMemEnd) {
    #define		d	((memType)dstPtr - (memType)pApm->FbBase)
    		A(WaitForFifo)(pApm, 1);
    		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
    		switch(pApm->CurrentLayout.bitsPerPixel) {
    		case 8: case 24:
    		    SETSOURCEOFF((d & 0xFFF000) << 4 |
    				(d & 0xFFF));
    		    break;
    		case 16:
    		    SETSOURCEOFF((d & 0xFFE000) << 3 |
    				((d & 0x1FFE) >> 1));
    		    break;
    		case 32:
    		    SETSOURCEOFF((d & 0xFFC000) << 2 |
    				((d & 0x3FFC) >> 2));
    		    break;
    		}
    #undef		d
    	    }
    	    else {
    		(*pApm->AccelInfoRec->Sync)(pScrn);
    		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
    		SETSOURCEOFF(pApm->ScratchMem);
    	    }
    	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * h) + 4) & ~7;
    	    for (i = h; i-- > 0; ) {
    		for (j = wrd; j-- > 0; ) {
    		    if (i || j)
    			*dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
    		    else if (srcwidth > -8) {
    			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[2]];
    			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[1]];
    			((CARD8 *)dstPtr)[2] = byte_reversed[((CARD8 *)src)[0]];
    			dstPtr = (CARD32 *)(3 + (CARD8 *)dstPtr);
    		    }
    		    else if (srcwidth > -16) {
    			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[1]];
    			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[0]];
    			dstPtr = (CARD32 *)(2 + (CARD8 *)dstPtr);
    		    }
    		    else {
    			*(CARD8 *)dstPtr = byte_reversed[*(CARD8 *)src];
    			dstPtr = (CARD32 *)(1 + (CARD8 *)dstPtr);
    		    }
    		    src += 4;
    		}
    		src += srcwidth;
    	    }
    	    A(WaitForFifo)(pApm, 1);
    #ifdef FASTER
    	    SETWIDTHHEIGHT(w, h);
    #else
    	    SETDEC(c);
    #endif
    	}
        }
        pApm->apmClip = apmClip;
    }
    
    static void
    A(TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
    		    int skipleft, int startline, 
    		    unsigned int **glyphs, int glyphWidth,
    		    int fg, int bg, int rop, unsigned planemask)
    {
        CARD32 *base, *base0;
        GlyphScanlineFuncPtr GlyphFunc;
        static GlyphScanlineFuncPtr *GlyphTab = NULL;
        int w2, h2, dwords;
    
        if (!GlyphTab) GlyphTab = XAAGetGlyphScanlineFuncLSBFirst();
        GlyphFunc = GlyphTab[glyphWidth - 1];
    
        w2 = w + skipleft;
        h2 = h;
        dwords = (w2 + 31) >> 5;
        dwords <<= 2;
    
        base0 = base = malloc(dwords * h);
        if (!base)
    	return;		/* Should not happen : it's rather small... */
    
        while(h--) {
    	base = (*GlyphFunc)(base, glyphs, startline++, w2, glyphWidth);
        }
    
        A(WriteBitmap)(pScrn, x, y, w, h2, (unsigned char *)base0, dwords,
    		    skipleft, fg, bg, rop, planemask);
    
        free(base0);
    }
    
    static void A(SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty,
    				          int fg, int bg, int rop,
    				          unsigned int planemask)
    {
        APMDECL(pScrn);
    
        DPRINTNAME(SetupForMono8x8PatternFill);
        pApm->apmTransparency = (pApm->Chipset >= AT3D) && (bg == -1);
        pApm->Bg8x8 = bg;
        pApm->Fg8x8 = fg;
        pApm->rop = apmROP[rop];
        A(WaitForFifo)(pApm, 3 + pApm->apmClip);
        if (bg == -1)
    	SETBACKGROUNDCOLOR(fg + 1);
        else
    	SETBACKGROUNDCOLOR(bg);
        SETFOREGROUNDCOLOR(fg);
        if (pApm->Chipset >= AT3D)
    	SETROP(apmROP[rop] & 0xF0);
        else
    	SETROP((apmROP[rop] & 0xF0) | 0x0A);
        if (pApm->apmClip) {
    	SETCLIP_CTRL(0);
    	pApm->apmClip = FALSE;
        }
    }
    
    static void A(SubsequentMono8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
    					        int paty, int x, int y,
    					        int w, int h)
    {
        APMDECL(pScrn);
    
        DPRINTNAME(SubsequentMono8x8PatternFillRect);
        SETDESTXY(x, y);
        UPDATEDEST(x, y + h + 1);
        A(WaitForFifo)(pApm, 6);
        if (pApm->Chipset == AT24 && pApm->Bg8x8 != -1) {
    	SETROP(pApm->rop);
    	SETFOREGROUNDCOLOR(pApm->Bg8x8);
    #ifdef FASTER
    	SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
    		DEC_DEST_XY | DEC_QUICKSTART_ONDIMX);
    	SETWIDTHHEIGHT(w, h);
    #else
    	SETWIDTHHEIGHT(w, h);
    	SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
    		DEC_DEST_XY | DEC_START);
    #endif
    	A(WaitForFifo)(pApm, 6);
    	SETROP((pApm->rop & 0xF0) | 0x0A);
    	SETFOREGROUNDCOLOR(pApm->Fg8x8);
        }
        SETPATTERN(patx, paty);
    #ifdef FASTER
        SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
    	    DEC_DEST_XY | DEC_PATTERN_88_1bMONO | DEC_DEST_UPD_TRCORNER |
    	    (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) |
    	    DEC_QUICKSTART_ONDIMX);
        SETWIDTHHEIGHT(w, h);
    #else
        SETWIDTHHEIGHT(w, h);
        SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
    	    DEC_DEST_XY | DEC_PATTERN_88_1bMONO | DEC_DEST_UPD_TRCORNER |
    	    (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) |
    	    DEC_START);
    #endif
    }
    
    #if 0
    static void
    A(SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, int bg,
    					int rop, unsigned int planemask)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SetupForCPUToScreenColorExpandFill);
      if (bg == -1)
      {
    #ifndef FASTER
        pApm->apmTransparency = TRUE;
        A(WaitForFifo)(pApm, 3);
    #else
        A(WaitForFifo)(pApm, 4);
        SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
          DEC_SOURCE_TRANSPARENCY | DEC_SOURCE_MONOCHROME | DEC_QUICKSTART_ONDIMX |
          DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC);
    #endif
        SETFOREGROUNDCOLOR(fg);
        SETBACKGROUNDCOLOR(fg+1);
      }
      else
      {
    #ifndef FASTER
        pApm->apmTransparency = FALSE;
        A(WaitForFifo)(pApm, 3);
    #else
        A(WaitForFifo)(pApm, 4);
        SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
    	   DEC_DEST_UPD_TRCORNER | DEC_SOURCE_MONOCHROME |
    	   DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
    #endif
        SETFOREGROUNDCOLOR(fg);
        SETBACKGROUNDCOLOR(bg);
      }
      SETROP(apmROP[rop]);
    }
    
    static void
    A(SubsequentCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y,
    					int w, int h, int skipleft)
    {
      APMDECL(pScrn);
    #ifndef FASTER
      u32 c;
    #endif
    
      DPRINTNAME(SubsequentCPUToScreenColorExpandFill);
    #ifndef FASTER
      c = DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
          DEC_SOURCE_MONOCHROME | DEC_START | DEC_DEST_UPD_TRCORNER |
          pApm->CurrentLayout.Setup_DEC;
    
      if (pApm->apmTransparency)
        c |= DEC_SOURCE_TRANSPARENCY;
    
      A(WaitForFifo)(pApm, 7);
    #else
      A(WaitForFifo)(pApm, 6);
    #endif
    
      SETCLIP_LEFTTOP(x+skipleft, y);
      SETCLIP_RIGHTBOT(x+w-1, y+h-1);
      SETCLIP_CTRL(0x01);
      pApm->apmClip = TRUE;
      SETSOURCEX(0); /* According to manual, it just has to be zero */
      SETDESTXY(x, y);
      SETWIDTHHEIGHT((w + 31) & ~31, h);
      UPDATEDEST(x + ((w + 31) & ~31), y);
    
    #ifndef FASTER
      SETDEC(c);
    #endif
    }
    #endif
    
    static void
    A(SetupForImageWrite)(ScrnInfoPtr pScrn, int rop, unsigned int planemask,
    		      int trans_color, int bpp, int depth)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SetupForImageWrite);
      if (trans_color != -1)
      {
    #ifndef FASTER
        pApm->apmTransparency = TRUE;
        A(WaitForFifo)(pApm, 3);
    #else
        A(WaitForFifo)(pApm, 4);
        SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
    	  DEC_SOURCE_TRANSPARENCY | DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
    #endif
        SETBACKGROUNDCOLOR(trans_color);
      }
      else {
    #ifndef FASTER
        pApm->apmTransparency = FALSE;
        A(WaitForFifo)(pApm, 2);
    #else
        A(WaitForFifo)(pApm, 3);
        SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
    	  DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
    #endif
      }
    
      SETROP(apmROP[rop]);
    }
    
    static void
    A(SubsequentImageWriteRect)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
    			    int skipleft)
    {
      APMDECL(pScrn);
    #ifndef FASTER
      u32 c;
    #endif
    
      DPRINTNAME(SubsequentImageWriteRect);
    #ifndef FASTER
      c = DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
          DEC_START | pApm->CurrentLayout.Setup_DEC;
    
      if (pApm->apmTransparency)
        c |= DEC_SOURCE_TRANSPARENCY;
    
      if (pApm->Chipset >= AT24)
          A(WaitForFifo)(pApm, 7);
      else
          A(WaitForFifo)(pApm, 3);
    #else
      if (pApm->Chipset >= AT24)
          A(WaitForFifo)(pApm, 6);
      else
          A(WaitForFifo)(pApm, 3);
    #endif
    
      SETCLIP_LEFTTOP(x+skipleft, y);
      SETCLIP_RIGHTBOT(x+w-1, y+h-1);
      SETCLIP_CTRL(0x01);
      pApm->apmClip = TRUE;
      if (pApm->Chipset < AT24)
          A(WaitForFifo)(pApm, 4);
      SETSOURCEX(0); /* According to manual, it just has to be zero */
      SETDESTXY(x, y);
      SETWIDTHHEIGHT((w + 3) & ~3, h);
    
    #ifndef FASTER
      SETDEC(c);
    #endif
    }
    
    static void
    A(SubsequentScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y,
    					   int w, int h, int srcx, int srcy,
    					   int offset)
    {
      APMDECL(pScrn);
      u32 c;
    
      DPRINTNAME(SubsequentScreenToScreenColorExpandFill);
    #ifdef FASTER
      c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
          DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC;
    #else
      c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
          DEC_START | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC;
    #endif
    
      if (pApm->apmTransparency)
        c |= DEC_SOURCE_TRANSPARENCY;
    
      if (srcy >= pApm->CurrentLayout.Scanlines) {
          struct ApmStippleCacheRec *pCache;
          CARD32	dist;
    
          /*
           * Offscreen linear stipple
           */
          pCache = &pApm->apmCache[srcy / pApm->CurrentLayout.Scanlines - 1];
          if (w != pCache->apmStippleCache.w * pApm->CurrentLayout.bitsPerPixel) {
    	  A(WaitForFifo)(pApm, 3);
    	  SETCLIP_LEFTTOP(x, y);
    	  SETCLIP_RIGHTBOT(x + w - 1, y + h - 1);
    	  SETCLIP_CTRL(0x01);
    	  pApm->apmClip = TRUE;
    	  w = pCache->apmStippleCache.w * pApm->CurrentLayout.bitsPerPixel;
    	  x -= srcx - pCache->apmStippleCache.x + offset;
    	  srcx = (srcy - pCache->apmStippleCache.y) & 7;
    	  srcy -= srcx;
    	  y -= srcx;
    	  h += srcx;
    	  srcx = pCache->apmStippleCache.x;
          }
          else if (pApm->apmClip) {
    	  A(WaitForFifo)(pApm, 1);
    	  SETCLIP_CTRL(0x00);
    	  pApm->apmClip = FALSE;
          }
          srcx += (srcy - pCache->apmStippleCache.y) * pCache->apmStippleCache.w;
          srcy = pCache->apmStippleCache.y % pApm->CurrentLayout.Scanlines;
          dist = srcx + srcy * pApm->CurrentLayout.displayWidth;
          srcx = dist & 0xFFF;
          srcy = dist >> 12;
          c |= DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR;
      }
      else if (offset) {
          A(WaitForFifo)(pApm, 3);
          SETCLIP_LEFTTOP(x, y);
          SETCLIP_RIGHTBOT(x + w, y + h);
          SETCLIP_CTRL(0x01);
          pApm->apmClip = TRUE;
          w += offset;
          x -= offset;
      }
      else if (pApm->apmClip) {
          A(WaitForFifo)(pApm, 1);
          SETCLIP_CTRL(0x00);
          pApm->apmClip = FALSE;
      }
    
      A(WaitForFifo)(pApm, 4);
    
      SETSOURCEXY(srcx, srcy);
      SETDESTXY(x, y);
    
    #ifdef FASTER
      SETDEC(c);
      SETWIDTHHEIGHT(w, h);
    #else
      SETWIDTHHEIGHT(w, h);
      SETDEC(c);
    #endif
      UPDATEDEST(x + w + 1, h);
    }
    
    static void
    A(SubsequentSolidBresenhamLine)(ScrnInfoPtr pScrn, int x1, int y1, int e1,
    				int e2, int err, int length, int octant)
    {
      APMDECL(pScrn);
    #ifdef FASTER
      u32 c = DEC_QUICKSTART_ONDIMX | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX |
    	  pApm->CurrentLayout.Setup_DEC;
    #else
      u32 c = DEC_START | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX | pApm->CurrentLayout.Setup_DEC;
    #endif
      int	tmp;
    
      DPRINTNAME(SubsequentSolidBresenhamLine);
    
      A(WaitForFifo)(pApm, 5);
      SETDESTXY(x1,y1);
      SETDDA_ERRORTERM(err);
      SETDDA_ADSTEP(e1, e2);
    
      if (octant & YMAJOR) {
        c |= DEC_MAJORAXIS_Y;
        tmp = e1; e1 = e2; e2 = tmp;
      }
      else
        c |= DEC_MAJORAXIS_X;
    
      if (octant & XDECREASING) {
        c |= DEC_DIR_X_NEG;
        e1 = -e1;
      }
      else
        c |= DEC_DIR_X_POS;
    
      if (octant & YDECREASING) {
        c |= DEC_DIR_Y_NEG;
        e2 = -e2;
      }
      else
        c |= DEC_DIR_Y_POS;
    
    #ifdef FASTER
      SETDEC(c);
      SETWIDTH(length);
    #else
      SETWIDTH(length);
      SETDEC(c);
    #endif
    
      if (octant & YMAJOR)
        UPDATEDEST(x1 + e1 / 2, y1 + e2 / 2);
      else
        UPDATEDEST(x1 + e2 / 2, y1 + e1 / 2);
      if (pApm->apmClip)
      {
        pApm->apmClip = FALSE;
        A(WaitForFifo)(pApm, 1);
        SETCLIP_CTRL(0);
      }
    }
    
    static void
    A(SubsequentSolidBresenhamLine6422)(ScrnInfoPtr pScrn, int x1, int y1, int e1,
    				int e2, int err, int length, int octant)
    {
      APMDECL(pScrn);
    #ifdef FASTER
      u32 c = DEC_QUICKSTART_ONDIMX | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX |
    	  pApm->CurrentLayout.Setup_DEC;
    #else
      u32 c = DEC_START | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX | pApm->CurrentLayout.Setup_DEC;
    #endif
      int	tmp;
    
      DPRINTNAME(SubsequentSolidBresenhamLine6422);
    
      A(WaitForFifo)(pApm, 1);
      SETDESTXY(x1,y1);
      A(WaitForFifo)(pApm, 4);
      SETDDA_ERRORTERM(err);
      SETDDA_ADSTEP(e1, e2);
    
      if (octant & YMAJOR) {
        c |= DEC_MAJORAXIS_Y;
        tmp = e1; e1 = e2; e2 = tmp;
      }
      else
        c |= DEC_MAJORAXIS_X;
    
      if (octant & XDECREASING) {
        c |= DEC_DIR_X_NEG;
        e1 = -e1;
      }
      else
        c |= DEC_DIR_X_POS;
    
      if (octant & YDECREASING) {
        c |= DEC_DIR_Y_NEG;
        e2 = -e2;
      }
      else
        c |= DEC_DIR_Y_POS;
    
    #ifdef FASTER
      SETDEC(c);
      SETWIDTH(length);
    #else
      SETWIDTH(length);
      SETDEC(c);
    #endif
    
      if (octant & YMAJOR)
        UPDATEDEST(x1 + e1 / 2, y1 + e2 / 2);
      else
        UPDATEDEST(x1 + e2 / 2, y1 + e1 / 2);
      if (pApm->apmClip)
      {
        pApm->apmClip = FALSE;
        A(WaitForFifo)(pApm, 1);
        SETCLIP_CTRL(0);
      }
    }
    
    static void
    A(SetClippingRectangle)(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
    {
      APMDECL(pScrn);
    
      DPRINTNAME(SetClippingRectangle);
      A(WaitForFifo)(pApm, 3);
      SETCLIP_LEFTTOP(x1,y1);
      SETCLIP_RIGHTBOT(x2,y2);
      SETCLIP_CTRL(0x01);
      pApm->apmClip = TRUE;
    }
    
    static void
    A(SyncBlt)(ApmPtr pApm)
    {
        int again = (pApm->Chipset == AP6422);
    
        do {
           while (!(STATUS() & STATUS_HOSTBLTBUSY))
    	   ;
        }
        while (again--);	/* See remark in Sync6422 */
    }
    static void
    A(WritePixmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
    	       unsigned char *src, int srcwidth, int rop,
    	       unsigned int planemask, int trans, int bpp, int depth)
    {
        APMDECL(pScrn);
        int dwords, skipleft, Bpp = bpp >> 3;
        Bool beCareful = FALSE;
        unsigned char *dst = ((unsigned char *)pApm->FbBase) + x * Bpp + y * pApm->CurrentLayout.bytesPerScanline;
        int PlusOne = 0, mask, count;
    
        DPRINTNAME(WritePixmap);
        if (rop == GXnoop)
    	return;
        /*
         * The function seems to crash more than it feels good. I hope that a
         * good sync will help. This sync is anyway needed for direct write.
         */
        (*pApm->AccelInfoRec->Sync)(pScrn);
        /*
         * First the fast case : source and dest have same alignment. Doc says
         * it's faster to do it here, which may be true since one has to read
         * the chip when CPU to screen-ing.
         */
        if ((skipleft = (long)src & 3L) == ((long)dst & 3L) && rop == GXcopy) {
    	int skipright;
    
    	if (skipleft)
    	    skipleft = 4 - skipleft;
    	dwords = (skipright = w * Bpp - skipleft) >> 2;
    	skipright %= 4;
    	if (!skipleft && !skipright)
    	    while (h-- > 0) {
    		CARD32 *src2 = (CARD32 *)src;
    		CARD32 *dst2 = (CARD32 *)dst;
    
    		for (count = dwords; count-- > 0; )
    		    *dst2++ = *src2++;
    		src += srcwidth;
    		dst += pApm->CurrentLayout.bytesPerScanline;
    	    }
    	else if (!skipleft)
    	    while (h-- > 0) {
    		CARD32 *src2 = (CARD32 *)src;
    		CARD32 *dst2 = (CARD32 *)dst;
    
    		for (count = dwords; count-- > 0; )
    		    *dst2++ = *src2++;
    		for (count = skipright; count-- > 0; )
    		    ((char *)dst2)[count] = ((char *)src2)[count];
    		src += srcwidth;
    		dst += pApm->CurrentLayout.bytesPerScanline;
    	    }
    	else if (!skipright)
    	    while (h-- > 0) {
    		CARD32 *src2 = (CARD32 *)(src + skipleft);
    		CARD32 *dst2 = (CARD32 *)(dst + skipleft);
    
    		for (count = skipleft; count-- > 0; )
    		    dst[count] = src[count];
    		for (count = dwords; count-- > 0; )
    		    *dst2++ = *src2++;
    		src += srcwidth;
    		dst += pApm->CurrentLayout.bytesPerScanline;
    	    }
    	else
    	    while (h-- > 0) {
    		CARD32 *src2 = (CARD32 *)(src + skipleft);
    		CARD32 *dst2 = (CARD32 *)(dst + skipleft);
    
    		for (count = skipleft; count-- > 0; )
    		    dst[count] = src[count];
    		for (count = dwords; count-- > 0; )
    		    *dst2++ = *src2++;
    		for (count = skipright; count-- > 0; )
    		    ((char *)dst2)[count] = ((char *)src2)[count];
    		src += srcwidth;
    		dst += pApm->CurrentLayout.bytesPerScanline;
    	    }
    
    	return;
        }
    
        if (skipleft) {
    	if (Bpp == 3)
    	   skipleft = 4 - skipleft;
    	else
    	   skipleft /= Bpp;
    
    	if (x < skipleft) {
    	   skipleft = 0;
    	   beCareful = TRUE;
    	   goto BAD_ALIGNMENT;
    	}
    
    	x -= skipleft;
    	w += skipleft;
    
    	if (Bpp == 3)
    	   src -= 3 * skipleft;
    	else   /* is this Alpha friendly ? */
    	   src = (unsigned char*)((long)src & ~0x03L);
        }
    
    BAD_ALIGNMENT:
    
        dwords = ((w * Bpp) + 3) >> 2;
        mask = (pApm->CurrentLayout.bitsPerPixel / 8) - 1;
    
        if (dwords & mask) {
    	/*
    	 * Experimental...
    	 * It seems the AT3D needs a padding of scanline to a multiple of
    	 * 4 pixels, not only bytes.
    	 */
    	PlusOne = mask - (dwords & mask) + 1;
        }
    
        A(SetupForImageWrite)(pScrn, rop, planemask, trans, bpp, depth);
        A(SubsequentImageWriteRect)(pScrn, x, y, w, h, skipleft);
    
        if (beCareful) {
    	/* in cases with bad alignment we have to be careful not
    	   to read beyond the end of the source */
    	if (((x * Bpp) + (dwords << 2)) > srcwidth) h--;
    	else beCareful = FALSE;
        }
    
        srcwidth -= (dwords << 2);
    
        while (h--) {
    	for (count = dwords; count-- > 0; ) {
    	    A(SyncBlt)(pApm);
    	    *(CARD32*)pApm->BltMap = *(CARD32*)src;
    	    src += 4;
    	}
    	src += srcwidth;
    	for (count = PlusOne; count-- > 0; ) {
    	    int	status;
    
    	    while (!((status = STATUS()) & STATUS_HOSTBLTBUSY))
    		if (!(status & STATUS_ENGINEBUSY))
    		    break;
    	    if (pApm->Chipset == AP6422)	/* See remark in Sync6422 */
    		while (!((status = STATUS()) & STATUS_HOSTBLTBUSY))
    		    if (!(status & STATUS_ENGINEBUSY))
    			break;
    	    if (status & STATUS_ENGINEBUSY)
    		*(CARD32*)pApm->BltMap = 0x00000000;
    	}
        }
        if (beCareful) {
           int shift = ((long)src & 0x03L) << 3;
    
           if (--dwords) {
    	    for (count = dwords >> 2; count-- > 0; ) {
    		A(SyncBlt)(pApm);
    		*(CARD32*)pApm->BltMap = *(CARD32*)src;
    		src += 4;
    	    }
           }
           A(SyncBlt)(pApm);
           *((CARD32*)pApm->BltMap) = *((CARD32*)src) >> shift;
        }
    
        pApm->apmClip = FALSE;
        A(WaitForFifo)(pApm, 1);
        SETCLIP_CTRL(0);
    }
    
    static void 
    A(FillImageWriteRects)(ScrnInfoPtr pScrn, int rop, unsigned int planemask,
    			int nBox, BoxPtr pBox, int xorg, int yorg,
    			PixmapPtr pPix)
    {
        XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
        int x, y, phaseY, phaseX, height, width, blit_w;
        int pHeight = pPix->drawable.height;
        int pWidth = pPix->drawable.width;
        int depth = pPix->drawable.depth;
        int bpp = pPix->drawable.bitsPerPixel;
        unsigned char *pSrc;
        int srcwidth = pPix->devKind;
    
        while(nBox--) {
    	x = pBox->x1;
    	y = pBox->y1;
    	phaseY = (pBox->y1 - yorg) % pHeight;
    	if(phaseY < 0) phaseY += pHeight;
    	phaseX = (x - xorg) % pWidth;
    	pSrc = (unsigned char *)pPix->devPrivate.ptr +
    				    phaseX * pPix->drawable.bitsPerPixel / 8;
    	if(phaseX < 0) phaseX += pWidth;
    	height = pBox->y2 - pBox->y1;
    	width = pBox->x2 - x;
    	
    	while(1) {
    	    int		ch = height, cp = phaseY, cy = y;
    
    	    blit_w = pWidth - phaseX;
    	    if(blit_w > width) blit_w = width;
    
    	    while (ch > 0) {
    		int	h = MIN(pHeight - cp, ch);
    
    		A(WritePixmap)(pScrn, x, cy, blit_w, h, pSrc + cp * srcwidth,
    				srcwidth, rop, planemask, FALSE, bpp, depth);
    		cy += h;
    		ch -= h;
    		cp = 0;
    	    }
    
    	    width -= blit_w;
    	    if(!width) break;
    	    x += blit_w;
    	    phaseX = (phaseX + blit_w) % pWidth;
    	}
    	pBox++;
        }
    
        SET_SYNC_FLAG(infoRec);
    }
    
    static void A(SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn,int patx,int paty,
    				           int rop, unsigned int planemask,
    					   int transparency_color)
    {
        APMDECL(pScrn);
    
        DPRINTNAME(SetupForColor8x8PatternFillRect);
        if (transparency_color != -1) {
    #ifndef FASTER
    	pApm->apmTransparency = TRUE;
    	A(WaitForFifo)(pApm, 2 + pApm->apmClip);
    #else
    	A(WaitForFifo)(pApm, 3 + pApm->apmClip);
    	SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
    	    DEC_DEST_XY | DEC_PATTERN_88_8bCOLOR | DEC_SOURCE_TRANSPARENCY |
    	    DEC_QUICKSTART_ONDIMX);
    #endif
    	SETBACKGROUNDCOLOR(transparency_color);
        }
        else {
    #ifndef FASTER
    	pApm->apmTransparency = FALSE;
    	A(WaitForFifo)(pApm, 1 + pApm->apmClip);
    #else
    	A(WaitForFifo)(pApm, 2 + pApm->apmClip);
    	SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
    	    DEC_DEST_XY | DEC_PATTERN_88_8bCOLOR | DEC_QUICKSTART_ONDIMX);
    #endif
        }
        if (pApm->apmClip) {
    	SETCLIP_CTRL(0);
    	pApm->apmClip = FALSE;
        }
        SETROP(apmROP[rop]);
    }
    
    static void A(SubsequentColor8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
    					         int paty, int x, int y,
    					         int w, int h)
    {
        APMDECL(pScrn);
    
        DPRINTNAME(SubsequentColor8x8PatternFillRect);
    #ifndef FASTER
        A(WaitForFifo)(pApm, 5);
    #else
        A(WaitForFifo)(pApm, 4);
    #endif
        SETSOURCEXY(patx, paty);
        SETDESTXY(x, y);
        SETWIDTHHEIGHT(w, h);
        UPDATEDEST(x + w + 1, y);
    #ifndef FASTER
        SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
    	    DEC_DEST_XY | (pApm->apmTransparency * DEC_SOURCE_TRANSPARENCY) |
    	    DEC_PATTERN_88_8bCOLOR | DEC_START);
    #endif
    }
    #endif
    
    static void
    A(Sync)(ScrnInfoPtr pScrn)
    {
      APMDECL(pScrn);
      volatile u32 i, stat;
    
      for(i = 0; i < MAXLOOP; i++) {
        stat = STATUS();
        if ((!(stat & (STATUS_HOSTBLTBUSY | STATUS_ENGINEBUSY))) &&
            ((stat & STATUS_FIFO) >= 8))
          break;
      }
      if (i == MAXLOOP) {
        unsigned int status = STATUS();
    
        WRXB(0x1FF, 0);
        if (!xf86ServerIsExiting())
    	FatalError("Hung in ApmSync" APM_SUFF_24 "(%d) (Status = 0x%08X)\n", pScrn->pScreen->myNum, status);
      }
      if (pApm->apmClip) {
        SETCLIP_CTRL(0);
        pApm->apmClip = FALSE;
      }
    }
    
    #if PSZ != 24
    static void
    A(Sync6422)(ScrnInfoPtr pScrn)
    {
      APMDECL(pScrn);
      volatile u32 i, j, stat;
    
      for (j = 0; j < 2; j++) {
          /*
           * From Henrik Harmsen :
           *
           * This is a kludge. We can't trust the status register. Don't
           * know why... We shouldn't be forced to read the status reg and get
           * a correct value more than once...
           */
          for(i = 0; i < MAXLOOP; i++) {
    	stat = STATUS();
    	if ((!(stat & (STATUS_HOSTBLTBUSY | STATUS_ENGINEBUSY))) &&
    	    ((stat & STATUS_FIFO) >= 4))
    	  break;
          }
      }
      if (i == MAXLOOP) {
        unsigned int status = STATUS();
    
        WRXB(0x1FF, 0);
        if (!xf86ServerIsExiting())
    	FatalError("Hung in ApmSync6422() (Status = 0x%08X)\n", status);
      }
      if (pApm->apmClip) {
        SETCLIP_CTRL(0);
        pApm->apmClip = FALSE;
      }
    }
    #endif
    #include "apm_video.c"
    
    
    #undef	RDXB
    #undef	RDXW
    #undef	RDXL
    #undef	WRXB
    #undef	WRXW
    #undef	WRXL
    #undef	ApmWriteSeq
    #define RDXB	RDXB_M
    #define RDXW	RDXW_M
    #define RDXL	RDXL_M
    #define WRXB	WRXB_M
    #define WRXW	WRXW_M
    #define WRXL	WRXL_M
    #define ApmWriteSeq(idx, val)	do { APMVGAB(0x3C4) = (idx); APMVGAB(0x3C5) = (val); break; } while(1)
    #undef DPRINTNAME
    #undef A
    #undef DEPTH
    #undef PSZ
    #undef APM_SUFF_24