text: /*
   * Copyright 2000 by Richard A. Hecker, California, United States
   *
   * Permission to use, copy, modify, distribute, and sell this software and its
   * documentation for any purpose is hereby granted without fee, provided that
   * the above copyright notice appear in all copies and that both that
   * copyright notice and this permission notice appear in supporting
   * documentation, and that the name of Richard Hecker not be used in
   * advertising or publicity pertaining to distribution of the software without
   * specific, written prior permission.  Richard Hecker makes no representations
   * about the suitability of this software for any purpose.  It is provided
   * "as is" without express or implied warranty.
   *
   * RICHARD HECKER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   * EVENT SHALL RICHARD HECKER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
   * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   * PERFORMANCE OF THIS SOFTWARE.
   *
   * Author:  Richard Hecker, hecker@cat.dfrc.nasa.gov
   *          Re-written for XFree86 v4.0
   * Previous driver (pre-XFree86 v4.0) by
   *          Annius V. Groenink (A.V.Groenink@zfc.nl, avg@cwi.nl),
   *          Dirk H. Hohndel (hohndel@suse.de),
   *          Portions: the GGI project & confidential CYRIX databooks.
   */
  /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/cyrix/cyrix_accel.c,v 1.3 2000/04/19 16:57:43 eich Exp $ */
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include "vgaHW.h"
  #include "xf86.h"
  #include "xf86_ansic.h"
  #include "xaalocal.h"
  #include "cyrix.h"
  #include "miline.h"
  #include "xf86_libc.h"
  #include "compiler.h"
  
  /* size of color expand source area (embedded in frame buffer) */
  #define CYRIXexpandSize       32768
  
  /* Raster operations are converted in such a way that we can use them to
     do planemask operations: lower nybble is NOP (pattern=planemask),
     upper nybble inverted X raster operation (bits 0 - 3 correspond to
     bits 3 - 0 and 7 - 4 in Windows style ROP).  In some routines,
     the role of source and pattern is inverted. */
  static const int windowsROPpatMask[16] = { 0x0A, 0x8A, 0x4A, 0xCA,
                                             0x2A, 0xAA, 0x6A, 0xEA,
                                             0x1A, 0x9A, 0x5A, 0xDA,
                                             0x3A, 0xBA, 0x7A, 0xFA };
  
  static const int windowsROPsrcMask[16] = { 0x22, 0xA2, 0x62, 0xE2,
                                             0x2A, 0xAA, 0x6A, 0xEA,
                                             0x26, 0xA6, 0x66, 0xE6,
                                             0x2E, 0xAE, 0x6E, 0xEE };
  
  /* Forward declaration of functions used in the driver */
  void CYRIXAccelSync(ScrnInfoPtr pScrn);
  void CYRIXSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop,
  				unsigned int planemask);
  void CYRIXSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y,
  					int w, int h);
  void CYRIXSetupForScreenToScreenCopy(ScrnInfoPtr, int xdir, int ydir,
  		int rop, unsigned int planemask, int transparency_color);
  void CYRIXSubsequentScreenToScreenCopy(ScrnInfoPtr, int x1, int y1, int x2,
  					int y2, int w, int h);
  void CYRIXSubsequentBresenhamLine(ScrnInfoPtr pScrn,int x1, int y1,
  				  int e1, int e2, int err, int length,
  				  int octant);
  void CYRIXSetupForColor8x8PatternFillRect(ScrnInfoPtr pScrn, int patternx,
  	int patterny, int rop, unsigned int planemask, int transparency_color);
  void CYRIXSubsequentColor8x8PatternFillRect(ScrnInfoPtr pScrn, int patternx,
  				int patterny, int x, int y, int w, int h);
  void CYRIXSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg,
  			int bg, int rop, unsigned int planemask);
  void CYRIXSubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int x,
  			int y, int w, int h, int skipleft);
  void InitPixmapCache(ScreenPtr pScreen, RegionPtr areas, pointer data);
  /* Info Rec for all these routines to use */
  
  /* Acceleration init function, sets up pointers to our accelerated functions */
  void 
  CYRIXAccelInit(ScreenPtr pScreen) 
  {	/* General acceleration flags */
  
  	CYRIXPrvPtr	pCyrix;
  	ScrnInfoPtr 	pScrn;
  	XAAInfoRecPtr localRecPtr;
  
  	pScrn = xf86Screens[pScreen->myNum];
  	pCyrix = CYRIXPTR(pScrn);
  	pCyrix->AccelInfoRec = localRecPtr = XAACreateInfoRec();
  	localRecPtr->Flags = PIXMAP_CACHE
  	                       | PW_BACKGROUND
  #if 0
  	                       | HARDWARE_PATTERN_MONO_TRANSPARENCY
  #endif
  	                       | HARDWARE_PATTERN_SCREEN_ORIGIN
  	                       | BIT_ORDER_IN_BYTE_MSBFIRST
  	                       | HARDWARE_PATTERN_PROGRAMMED_BITS;
  
  	/* Sync */
  	localRecPtr->Sync = CYRIXAccelSync;
  
  	/* Filled rectangles */
  	localRecPtr->SetupForSolidFill = 
  	    CYRIXSetupForSolidFill;
  	localRecPtr->SubsequentSolidFillRect = 
  	    CYRIXSubsequentSolidFillRect;
  	pCyrix->AccelInfoRec->PolyFillRectSolidFlags = NO_PLANEMASK;
  
  	/* ScreenToScreen copies */
  	localRecPtr->SetupForScreenToScreenCopy =
  	    CYRIXSetupForScreenToScreenCopy;
  	localRecPtr->SubsequentScreenToScreenCopy =
  	    CYRIXSubsequentScreenToScreenCopy;
  
  	pCyrix->AccelInfoRec->CopyAreaFlags = NO_PLANEMASK | GXCOPY_ONLY;
  
  #if 0
  	/* Bresenham lines - disable because of minor display errors */
  	localRecPtr->SubsequentBresenhamLine =
  	    CYRIXSubsequentBresenhamLine;
  	localRecPtr->ErrorTermBits = 15;
  #endif
  
  	/* 8x8 color-expanded patterns */
  	localRecPtr->SetupForColor8x8PatternFill =
  	    CYRIXSetupForColor8x8PatternFillRect;
  	localRecPtr->SubsequentColor8x8PatternFillRect =
  	    CYRIXSubsequentColor8x8PatternFillRect;
  
  	/* Color expansion */
  	localRecPtr->Color8x8PatternFillFlags =
  			BIT_ORDER_IN_BYTE_MSBFIRST | NO_PLANEMASK |
  			TRANSPARENCY_GXCOPY_ONLY | SCANLINE_PAD_DWORD;
  
  	/* Use two blit buffers in a row for text expansion
  	   (this is an undefendable fix to a text display distortion
  	   bug if we don't give XAA enough room, but the only thing that
  	   seems to make it work properly) */
  	localRecPtr->ColorExpandBase =
  	    (unsigned char*)(pCyrix->GXregisters + pCyrix->CYRIXbltBuf0Address);
  	localRecPtr->ColorExpandRange =
  	    pCyrix->CYRIXbltBufSize * 2;
  
  	localRecPtr->SetupForCPUToScreenColorExpandFill =
  	    CYRIXSetupForCPUToScreenColorExpandFill;
  	localRecPtr->SubsequentCPUToScreenColorExpandFill =
  	    CYRIXSubsequentCPUToScreenColorExpandFill;
  
  	/* calculate the pixel width of a blit buffer for convenience */
  	pCyrix->bltBufWidth = pCyrix->CYRIXbltBufSize / (pScrn->bitsPerPixel / 8);
  } 
  
  
  /* set colors - called through access macros in cyrix.h */
  static __inline__ void CYRIXsetColors01(ScrnInfoPtr pScrn, int reg,
  					int col0, int col1) {
  	CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
  	
      if (pScrn->bitsPerPixel == 16)
  		GX_REG(reg) = ((col1 & 0xFFFF) << 16) | (col0 & 0xFFFF);
  	else
  	{	col0 &= 0xFF;
  		col1 &= 0xFF;
  		GX_REG(reg) = (col1 << 24) | (col1 << 16) | (col0 << 8) | col0;
  }	}
  
  
  /* The generic Sync() function that waits for everything to
     be completed (e.g. before writing to the frame buffer
     directly). */
  void
  CYRIXAccelSync(ScrnInfoPtr pScrn)
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
  	
      if (pCyrix->setBlitModeOnSync)
  	{	pCyrix->setBlitModeOnSync = 0;
  		CYRIXsetupSync();
  		CYRIXsetBlitMode();
  	}
  	while (GX_REG(GP_BLIT_STATUS) &
  	       (BS_BLIT_BUSY|BS_PIPELINE_BUSY|BS_BLIT_PENDING));
  }
  
  
  /* Solid rectangles */
  void 
  CYRIXSetupForSolidFill(pScrn, color, rop, planemask)
  ScrnInfoPtr pScrn;
  int color, rop;
  unsigned int planemask;
  {
  	CYRIXPrvPtr	pCyrix;
  
  	pCyrix = CYRIXPTR(pScrn);
  	if (pCyrix->AccelInfoRec->PolyFillRectSolidFlags & GXCOPY_ONLY)
  	    rop = GXcopy;
  	if (pCyrix->AccelInfoRec->PolyFillRectSolidFlags & NO_PLANEMASK)
  	    planemask = 0xFFFF;
  	CYRIXsetupSync();
  	CYRIXsetSourceColors01(pScrn, color, color);
  	CYRIXsetPatColors01(pScrn, planemask, 0);
  	CYRIXsetPatMode(rop, RM_PAT_DISABLE);
  	pCyrix->blitMode = BM_READ_SRC_NONE | BM_WRITE_FB | BM_SOURCE_EXPAND
  	    | IfDest(rop, planemask, BM_READ_DST_FB0);
  	pCyrix->vectorMode = IfDest(rop, planemask, VM_READ_DST_FB);
  }
      
      
  void 
  CYRIXSubsequentSolidFillRect(pScrn, x, y, w, h)
  ScrnInfoPtr pScrn;
  int x, y, w, h;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
  
      /* divide the operation into columns if required; use twice the
             blit buffer width because buffer 0 will overflow into buffer 1 */
  	while (w > 2 * pCyrix->bltBufWidth)
  	{	CYRIXSubsequentSolidFillRect(pScrn, x, y,
  					     2 * pCyrix->bltBufWidth, h);
  		x += 2 * pCyrix->bltBufWidth;
  		w -= 2 * pCyrix->bltBufWidth;
  	}
  	CYRIXsetupSync();
  	CYRIXsetDstXY(x, y);
  	CYRIXsetWH(w, h);
  	CYRIXsetBlitMode();
  }
  
  
  /* Screen to screen copies */
  void 
  CYRIXSetupForScreenToScreenCopy(pScrn, xdir, ydir, rop,
  				planemask, transparency_color)
  ScrnInfoPtr pScrn;
  int xdir, ydir;
  int rop;
  unsigned int planemask;
  int transparency_color;
  {
  	CYRIXPrvPtr	pCyrix;
  
  	pCyrix = CYRIXPTR(pScrn);
  	if (pCyrix->AccelInfoRec->CopyAreaFlags & NO_PLANEMASK)
  		planemask = 0xFFFF;
  	if (pCyrix->AccelInfoRec->CopyAreaFlags & GXCOPY_ONLY)
  		rop = GXcopy;
  	if (pCyrix->AccelInfoRec->CopyAreaFlags & NO_TRANSPARENCY)
  		transparency_color = -1;
  
  	CYRIXsetupSync();
  	CYRIXsetPatColors01(pScrn, planemask, 0);
  
  	if (transparency_color == -1)
  	{	CYRIXsetPatMode(rop, RM_PAT_DISABLE);
  		pCyrix->transMode = 0;
  	}
  	else
  	{	CYRIXsetPatModeTrans(RM_PAT_DISABLE);
  		pCyrix->transMode = 1;
  
  		if (pCyrix->AccelInfoRec->CopyAreaFlags &
  						TRANSPARENCY_GXCOPY_ONLY)
  			rop = GXcopy;
  
  		/* fill blit buffer 1 with the transparency color */
  		if (pScrn->bitsPerPixel == 16)
  		{	int              k   = pCyrix->CYRIXbltBufSize / 4;
  			CARD32           val = (transparency_color << 16) |
  			                       transparency_color;
  			volatile CARD32* buf = &(GX_REG(pCyrix->CYRIXbltBuf1Address));
  
  			while (--k >= 0) buf[k] = val;
  		}
  		else
  			memset(pCyrix->GXregisters + pCyrix->CYRIXbltBuf1Address,
  			       transparency_color, pCyrix->CYRIXbltBufSize);
  	}
  
  	pCyrix->blitMode = BM_READ_SRC_FB | BM_WRITE_FB | BM_SOURCE_COLOR
  	    | (pCyrix->transMode ? BM_READ_DST_NONE : IfDest(rop, planemask, BM_READ_DST_FB1))
  	    | (ydir < 0 ? BM_REVERSE_Y : 0);
  
  	pCyrix->copyXdir = xdir;
  }
  
  void 
  CYRIXSubsequentScreenToScreenCopy(pScrn, x1, y1, x2, y2, w, h)
  ScrnInfoPtr pScrn;
  int x1, y1, x2, y2, w, h;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
      int up       = (pCyrix->blitMode & BM_REVERSE_Y);
  
  	/* divide the operation into columns when necessary */
  	if (pCyrix->copyXdir < 0)
  	{	int x_offset = w - pCyrix->bltBufWidth;
  
  		while (x_offset > 0)
  		{	CYRIXSubsequentScreenToScreenCopy(pScrn, x1 + x_offset, y1,
  			                                  x2 + x_offset, y2,
  			                                  pCyrix->bltBufWidth, h);
  			x_offset -= pCyrix->bltBufWidth;
  			w -= pCyrix->bltBufWidth;
  	}	}
  	else while (w > pCyrix->bltBufWidth)
  	{	CYRIXSubsequentScreenToScreenCopy(pScrn, x1, y1, x2, y2,
  		                                  pCyrix->bltBufWidth, h);
  		x1 += pCyrix->bltBufWidth;
  		x2 += pCyrix->bltBufWidth;
  		w -= pCyrix->bltBufWidth;
  	}
  
  	CYRIXsetupSync();
  	CYRIXsetSrcXY(x1, (up ? (y1 + h - 1) : y1));
  	CYRIXsetDstXY(x2, (up ? (y2 + h - 1) : y2));
  
  	/* in transparent mode, one line reads the transparency color
  	   into a processor-internal register, and the remaining lines
  	   can be done in a single second pass */
  	if (pCyrix->transMode)
  	{	pCyrix->blitMode |= BM_READ_DST_BB1;
  		CYRIXsetWH(w, 1);
  		CYRIXsetBlitMode();
  		h--;
  		if (!h) return;
  		if (up) { y1--; y2--; }
  		else { y1++; y2++; }
  		CYRIXsetupSync();
  		pCyrix->blitMode &= ~(BM_READ_DST_BB1);
  	}
  	CYRIXsetWH(w, h);
  	CYRIXsetBlitMode();
  }
  
  
  /* Bresenham lines */
  void
  CYRIXSubsequentBresenhamLine(pScrn, x1, y1, e1, e2, err, length, octant)
  ScrnInfoPtr pScrn; int x1, y1, octant, err, e1, e2, length;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
      
      if (octant & YMAJOR) {
  	pCyrix->vectorMode = (pCyrix->vectorMode & VM_READ_DST_FB) | VM_Y_MAJOR;
  	if (!(octant & XDECREASING)) pCyrix->vectorMode |= VM_MINOR_INC;
  	if (!(octant & YDECREASING)) pCyrix->vectorMode |= VM_MAJOR_INC;
      } else {
  	pCyrix->vectorMode = (pCyrix->vectorMode & VM_READ_DST_FB) | VM_X_MAJOR;
  	if (!(octant & XDECREASING)) pCyrix->vectorMode |= VM_MAJOR_INC;
  	if (!(octant & YDECREASING)) pCyrix->vectorMode |= VM_MINOR_INC;
      }
      
      CYRIXsetupSync();
      CYRIXsetDstXY(x1, y1);
      CYRIXsetWH(length, (err & 0xFFFF));
      CYRIXsetSrcXY((e1 & 0xFFFF), (e2 & 0xFFFF));
      CYRIXsetVectorMode();
  }
  
  
  /* 8x8 pattern color expand */
  void CYRIXSetupForColor8x8PatternFillRect(pScrn, patternx, patterny,
  						rop, planemask, transparency_color)
  ScrnInfoPtr pScrn;
  int patternx, patterny;
  int rop, transparency_color;
  unsigned int planemask;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
      XAAInfoRecPtr localRecPtr = pCyrix->AccelInfoRec;
      
  	if (localRecPtr->Color8x8PatternFillFlags & NO_PLANEMASK)
  		planemask = 0xFFFF;
  	if ((transparency_color == -1) && (localRecPtr->Color8x8PatternFillFlags &
  						TRANSPARENCY_GXCOPY_ONLY))
  		rop = GXcopy;
  
  	CYRIXsetupSync();
  	CYRIXsetPatColors01(pScrn, (transparency_color == -1) ?
  					0 : transparency_color, planemask);
  	CYRIXsetPatData(patternx, patterny);
  	CYRIXsetPatModeX(rop, RM_PAT_MONO | ((transparency_color == -1) ?
  						RM_PAT_TRANSPARENT : 0));
  
  	pCyrix->blitMode = BM_READ_SRC_NONE | BM_WRITE_FB | BM_SOURCE_EXPAND |
  	         ((transparency_color == -1) ?
  		 IfDest(rop, planemask, BM_READ_DST_FB0) : BM_READ_DST_NONE);
  }
  
  void CYRIXSubsequentColor8x8PatternFillRect(pScrn, patternx, patterny, x, y, w, h)
  ScrnInfoPtr pScrn;
  int patternx, patterny;
  int x, y, w, h;
  {	CYRIXSubsequentSolidFillRect(pScrn, x, y, w, h);
  }
  
  
  /* CPU-to-screen color expansion */
  void CYRIXSetupForCPUToScreenColorExpandFill(pScrn, fg, bg, rop, planemask)
  ScrnInfoPtr pScrn;
  int bg, fg, rop;
  unsigned int planemask;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
      XAAInfoRecPtr localRecPtr = pCyrix->AccelInfoRec;
  
      int trans = (bg == -1);
  
  	if (trans && (localRecPtr->CPUToScreenColorExpandFillFlags &
  						TRANSPARENCY_GXCOPY_ONLY))
  		rop = GXcopy;
  
  	CYRIXsetupSync();
  	CYRIXsetSourceColors01(pScrn, trans ? 0 : bg, fg);
  	CYRIXsetPatColors01(pScrn, planemask, 0);
  
  	CYRIXsetPatMode(rop, RM_PAT_DISABLE | (trans ? RM_SRC_TRANSPARENT : 0));
  
  	/* this is formally incorrect: XAA may use both BB0 and BB1
  	   for the text source bitmap, so READ_DST_FB1 should not be
  	   used.  So far, this problem has not manifested itself in
  	   practice. */
  	pCyrix->blitMode = BM_READ_SRC_BB0 | BM_WRITE_FB | BM_SOURCE_EXPAND
  	    | (trans ? IfDest(rop, planemask, BM_READ_DST_FB1) : BM_READ_DST_NONE);
  }
  
  void CYRIXSubsequentCPUToScreenColorExpandFill(pScrn, x, y, w, h, skipleft)
  ScrnInfoPtr pScrn;
  int x, y, w, h;
  int skipleft;
  {
      CYRIXPrvPtr pCyrix = CYRIXPTR(pScrn);
      CYRIXsetupSync();
      CYRIXsetSrcXY(0, 0);
      CYRIXsetDstXY(x, y);
      CYRIXsetWH(w, h);
      
      CYRIXAccelSync(pScrn);
      pCyrix->setBlitModeOnSync = 1;
  }
  
  