apm_funcs.c revision 17a48c7c
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_funcs.c,v 1.18tsi Exp $ */
2
3#ifdef HAVE_CONFIG_H
4#include "config.h"
5#endif
6
7#define FASTER
8#ifndef PSZ
9#define PSZ	8
10#endif
11#ifdef IOP_ACCESS
12#  define APM_SUFF_IOP	"_IOP"
13#  undef	RDXB
14#  undef	RDXW
15#  undef	RDXL
16#  undef	WRXB
17#  undef	WRXW
18#  undef	WRXL
19#  undef	ApmWriteSeq
20#  define RDXB	RDXB_IOP
21#  define RDXW	RDXW_IOP
22#  define RDXL	RDXL_IOP
23#  define WRXB	WRXB_IOP
24#  define WRXW	WRXW_IOP
25#  define WRXL	WRXL_IOP
26#  define ApmWriteSeq(i, v)	wrinx(pApm->xport, i, v)
27#else
28#  define APM_SUFF_IOP	""
29#endif
30#if PSZ == 24
31#  define APM_SUFF_24	"24"
32#  ifdef IOP_ACCESS
33#    define A(s)		Apm##s##24##_IOP
34#  else
35#    define A(s)		Apm##s##24
36#  endif
37#else
38#  define APM_SUFF_24	""
39#  ifdef IOP_ACCESS
40#    define A(s)		Apm##s##_IOP
41#  else
42#    define A(s)		Apm##s
43#  endif
44#endif
45#define	DPRINTNAME(s)	do { xf86DrvMsgVerb(pScrn->pScreen->myNum, X_NOTICE, 6, "Apm" #s APM_SUFF_24 APM_SUFF_IOP "\n"); } while (0)
46
47#if PSZ == 24
48#undef SETSOURCEXY
49#undef SETDESTXY
50#undef SETWIDTH
51#undef SETWIDTHHEIGHT
52#undef UPDATEDEST
53#define SETSOURCEXY(x,y)	do { int off = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0x3FFF)) * 3); SETSOURCEOFF(((off & 0xFFF000) << 4) | (off & 0xFFF)); break;} while(1)
54#define SETDESTXY(x,y)	do { int off = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0x3FFF)) * 3); SETDESTOFF(((off & 0xFFF000) << 4) | (off & 0xFFF)); break;} while(1)
55#define SETWIDTH(w)		WRXW(0x58, ((w) & 0x3FFF) * 3)
56#define SETWIDTHHEIGHT(w,h)	WRXL(0x58, ((h) << 16) | (((w) & 0x3FFF) * 3))
57#define UPDATEDEST(x,y)		(void)(curr32[0x54 / 4] = ((((y) & 0xFFFF) * pApm->CurrentLayout.displayWidth + ((x) & 0xFFFF)) * 3))
58#endif
59
60/* Defines */
61#define MAXLOOP 1000000
62
63
64/* Local functions */
65static void A(Sync)(ScrnInfoPtr pScrn);
66static void A(SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop,
67					unsigned int planemask);
68static void A(SubsequentSolidFillRect)(ScrnInfoPtr pScrn, int x, int y,
69				       int w, int h);
70static void A(SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir,
71					  int rop, unsigned int planemask,
72                                          int transparency_color);
73static void A(SubsequentScreenToScreenCopy)(ScrnInfoPtr pScrn, int x1, int y1,
74					    int x2, int y2, int w, int h);
75#if PSZ != 24
76static void A(Sync6422)(ScrnInfoPtr pScrn);
77static void A(WriteBitmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
78			    unsigned char *src, int srcwidth, int skipleft,
79			    int fg, int bg, int rop, unsigned int planemask);
80static void A(TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
81				int skipleft, int startline,
82				unsigned int **glyphs, int glyphWidth,
83				int fg, int bg, int rop, unsigned planemask);
84static void A(SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty,
85				          int fg, int bg, int rop,
86				          unsigned int planemask);
87static void A(SubsequentMono8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
88					        int paty, int x, int y,
89					        int w, int h);
90#if 0
91static void A(SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int bg, int fg, int rop, unsigned int planemask);
92static void A(SubsequentCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y, int w, int h, int skipleft);
93#endif
94static void A(SetupForScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn,
95						     int fg, int bg, int rop,
96						     unsigned int planemask);
97static void A(SetupForImageWrite)(ScrnInfoPtr pScrn, int rop,
98				  unsigned int planemask, int trans_color,
99				  int bpp, int depth);
100static void A(SubsequentImageWriteRect)(ScrnInfoPtr pScrn, int x, int y,
101					int w, int h, int skipleft);
102static void A(SubsequentScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn,
103						       int x, int y,
104						       int w, int h,
105						       int srcx, int srcy,
106						       int offset);
107static void A(SubsequentSolidBresenhamLine)(ScrnInfoPtr pScrn, int x1, int y1, int octant, int err, int e1, int e2, int length);
108static void A(SubsequentSolidBresenhamLine6422)(ScrnInfoPtr pScrn, int x1, int y1, int octant, int err, int e1, int e2, int length);
109static void A(SetClippingRectangle)(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2);
110static void A(WritePixmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
111			   unsigned char *src, int srcwidth, int rop,
112			   unsigned int planemask, int trans, int bpp,
113			   int depth);
114static void A(FillImageWriteRects)(ScrnInfoPtr pScrn, int rop,
115				    unsigned int planemask,
116				    int nBox, BoxPtr pBox, int xorg, int yorg,
117				    PixmapPtr pPix);
118static void A(SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn,int patx,int paty,
119				           int rop, unsigned int planemask,
120					   int transparency_color);
121static void A(SubsequentColor8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
122					         int paty, int x, int y,
123					         int w, int h);
124#endif
125
126/* Inline functions */
127static __inline__ void
128A(WaitForFifo)(ApmPtr pApm, int slots)
129{
130  if (!pApm->UsePCIRetry) {
131    volatile int i;
132
133    for(i = 0; i < MAXLOOP; i++) {
134      if ((STATUS() & STATUS_FIFO) >= slots)
135	break;
136    }
137    if (i == MAXLOOP) {
138      unsigned int status = STATUS();
139
140      WRXB(0x1FF, 0);
141      if (!xf86ServerIsExiting())
142	  FatalError("Hung in WaitForFifo() (Status = 0x%08X)\n", status);
143    }
144  }
145}
146
147
148static void
149A(SetupForSolidFill)(ScrnInfoPtr pScrn, int color, int rop,
150			unsigned int planemask)
151{
152  APMDECL(pScrn);
153
154  DPRINTNAME(SetupForSolidFill);
155#ifdef FASTER
156  A(WaitForFifo)(pApm, 3 + pApm->apmClip);
157  SETDEC(DEC_QUICKSTART_ONDIMX | DEC_OP_RECT | DEC_DEST_UPD_TRCORNER |
158	  pApm->CurrentLayout.Setup_DEC);
159#else
160  A(WaitForFifo)(pApm, 2 + pApm->apmClip);
161#endif
162#if PSZ == 2
163  pApm->color = ((color & 0xFF0000) << 8) | ((color & 0xFF0000) >> 16) |
164		  ((color & 0xFF00) << 8) | ((color & 0xFF) << 16);
165#else
166  SETFOREGROUNDCOLOR(color);
167#endif
168
169  if (pApm->apmClip)  {
170    SETCLIP_CTRL(0);
171    pApm->apmClip = FALSE;
172  }
173
174  SETROP(apmROP[rop]);
175}
176
177static void
178A(SubsequentSolidFillRect)(ScrnInfoPtr pScrn, int x, int y, int w, int h)
179{
180  APMDECL(pScrn);
181
182  DPRINTNAME(SubsequentSolidFillRect);
183#if PSZ == 24
184#  ifndef FASTER
185  A(WaitForFifo)(pApm, 5);
186#  else
187  A(WaitForFifo)(pApm, 4);
188#  endif
189  SETOFFSET(3*(pApm->CurrentLayout.displayWidth - w));
190#if 0
191  switch ((((y * pApm->CurrentLayout.displayWidth + x)* 3) / 8) % 3) {
192  case 0:
193      SETFOREGROUNDCOLOR(pApm->color);
194      break;
195  case 1:
196      SETFOREGROUNDCOLOR((pApm->color << 8) | (pApm->color >> 16));
197      break;
198  case 2:
199      SETFOREGROUNDCOLOR(pApm->color >> 8);
200      break;
201  }
202#endif
203#else
204#  ifndef FASTER
205  A(WaitForFifo)(pApm, 3);
206#  else
207  A(WaitForFifo)(pApm, 2);
208#  endif
209#endif
210  SETDESTXY(x, y);
211  SETWIDTHHEIGHT(w, h);
212  UPDATEDEST(x + w + 1, y);
213#ifndef FASTER
214  SETDEC(DEC_START | DEC_OP_RECT | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC);
215#endif
216}
217
218static void
219A(SetupForScreenToScreenCopy)(ScrnInfoPtr pScrn, int xdir, int ydir, int rop,
220				unsigned int planemask, int transparency_color)
221{
222  unsigned char tmp;
223
224  APMDECL(pScrn);
225
226  DPRINTNAME(SetupForScreenToScreenCopy);
227
228  if (pApm->apmLock) {
229    /*
230     * This is just an attempt, because Daryll is tampering with MY registers.
231     */
232    tmp = (RDXB(0xDB) & 0xF4) |  0x0A;
233    WRXB(0xDB, tmp);
234    ApmWriteSeq(0x1B, 0x20);
235    ApmWriteSeq(0x1C, 0x2F);
236    pApm->apmLock = FALSE;
237  }
238
239  pApm->blitxdir = xdir;
240  pApm->blitydir = ydir;
241
242  pApm->apmTransparency = (transparency_color != -1);
243
244#ifdef FASTER
245  A(WaitForFifo)(pApm, 2 + (transparency_color != -1));
246  SETDEC(DEC_QUICKSTART_ONDIMX | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
247	  (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) | pApm->CurrentLayout.Setup_DEC |
248	  ((xdir < 0) ? DEC_DIR_X_NEG : DEC_DIR_X_POS) |
249	  ((ydir < 0) ? DEC_DIR_Y_NEG : DEC_DIR_Y_POS));
250#else
251  A(WaitForFifo)(pApm, 1 + (transparency_color != -1));
252#endif
253
254  if (transparency_color != -1)
255    SETBACKGROUNDCOLOR(transparency_color);
256
257  SETROP(apmROP[rop]);
258}
259
260static void
261A(SubsequentScreenToScreenCopy)(ScrnInfoPtr pScrn, int x1, int y1,
262				    int x2, int y2, int w, int h)
263{
264  APMDECL(pScrn);
265#ifndef FASTER
266  u32		c = pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0;
267#endif
268  u32		sx, dx, sy, dy;
269  int		i = y1 / pApm->CurrentLayout.Scanlines;
270
271  DPRINTNAME(SubsequentScreenToScreenCopy);
272  if (i && pApm->pixelStride) {
273#ifdef FASTER
274    A(WaitForFifo)(pApm, 1);
275    SETDEC(curr32[0x40 / 4] | (DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR));
276#else
277    c |= DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG;
278#endif
279    pApm->apmClip = TRUE;
280    A(WaitForFifo)(pApm, 3);
281    SETCLIP_LEFTTOP(x2, y2);
282    SETCLIP_RIGHTBOT(x2 + w - 1, y2 + h - 1);
283    SETCLIP_CTRL(1);
284    w = (pApm->pixelStride * 8) / pApm->CurrentLayout.bitsPerPixel;
285  }
286  else {
287#ifdef FASTER
288    A(WaitForFifo)(pApm, 1 + pApm->apmClip);
289    SETDEC(curr32[0x40 / 4] & ~(DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR));
290    if (pApm->apmClip)
291	SETCLIP_CTRL(0);
292    pApm->apmClip = FALSE;
293#else
294    if (pApm->apmClip) {
295	A(WaitForFifo)(pApm, 1);
296	SETCLIP_CTRL(0);
297	pApm->apmClip = FALSE;
298    }
299#endif
300  }
301  if (i) {
302      if (pApm->pixelStride) {
303	  x1 += (((y1 % pApm->CurrentLayout.Scanlines) - pApm->RushY[i - 1]) * pApm->pixelStride * 8) / pApm->CurrentLayout.bitsPerPixel;
304	  y1 = pApm->RushY[i - 1];
305      }
306      else
307	  y1 -= i * pApm->CurrentLayout.Scanlines;
308  }
309  if (pApm->blitxdir < 0)
310  {
311#ifndef FASTER
312    c |= DEC_DIR_X_NEG;
313#endif
314    sx = x1+w-1;
315    dx = x2+w-1;
316  }
317  else
318  {
319#ifndef FASTER
320    c |= DEC_DIR_X_POS;
321#endif
322    sx = x1;
323    dx = x2;
324  }
325
326  if (pApm->blitydir < 0)
327  {
328#ifndef FASTER
329    c |= DEC_DIR_Y_NEG | DEC_START | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
330	    pApm->CurrentLayout.Setup_DEC;
331#endif
332    sy = y1+h-1;
333    dy = y2+h-1;
334  }
335  else
336  {
337#ifndef FASTER
338    c |= DEC_DIR_Y_POS | DEC_START | DEC_OP_BLT | DEC_DEST_UPD_TRCORNER |
339	    pApm->CurrentLayout.Setup_DEC;
340#endif
341    sy = y1;
342    dy = y2;
343  }
344
345#if PSZ == 24
346#  ifndef FASTER
347  A(WaitForFifo)(pApm, 5);
348#  else
349  A(WaitForFifo)(pApm, 4);
350#  endif
351  if (pApm->blitxdir == pApm->blitydir)
352    SETOFFSET(3 * (pApm->CurrentLayout.displayWidth - w));
353  else
354    SETOFFSET(3 * (pApm->CurrentLayout.displayWidth + w));
355#else
356#  ifndef FASTER
357  A(WaitForFifo)(pApm, 4);
358#  else
359  A(WaitForFifo)(pApm, 3);
360#  endif
361#endif
362
363  if (i && pApm->pixelStride) {
364    register unsigned int off = sx + sy * pApm->CurrentLayout.displayWidth;
365
366    SETSOURCEOFF(((off & 0xFFF000) << 4) | (off & 0xFFF));
367  }
368  else
369    SETSOURCEXY(sx,sy);
370  SETDESTXY(dx,dy);
371  SETWIDTHHEIGHT(w,h);
372  UPDATEDEST(dx + (w + 1)*pApm->blitxdir, dy);
373
374#ifndef FASTER
375  SETDEC(c);
376#endif
377  if (i) A(Sync)(pScrn);	/* Only for AT3D */
378}
379
380
381#if PSZ != 24
382static void
383A(SetupForScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, int bg,
384					 int rop, unsigned int planemask)
385{
386  APMDECL(pScrn);
387
388  DPRINTNAME(SetupForScreenToScreenColorExpandFill);
389  A(WaitForFifo)(pApm, 3 + pApm->apmClip);
390  if (bg == -1)
391  {
392    SETFOREGROUNDCOLOR(fg);
393    SETBACKGROUNDCOLOR(fg+1);
394    pApm->apmTransparency = TRUE;
395  }
396  else
397  {
398    SETFOREGROUNDCOLOR(fg);
399    SETBACKGROUNDCOLOR(bg);
400    pApm->apmTransparency = FALSE;
401  }
402
403  SETROP(apmROP[rop]);
404}
405
406static void
407A(WriteBitmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
408		unsigned char *src, int srcwidth, int skipleft,
409		int fg, int bg, int rop, unsigned int planemask)
410{
411    APMDECL(pScrn);
412    Bool	beCareful, apmClip = FALSE;
413    int		wc, n, nc, wr, wrd;
414    CARD32	*dstPtr;
415#ifndef FASTER
416    int		c;
417#endif
418
419    DPRINTNAME(WriteBitmap);
420
421    if (w <= 0 && h <= 0)
422	return;
423
424    /*
425     * The function is a bit long, but the spirit is simple : put the monochrome
426     * data in scratch memory and color-expand it using the
427     * ScreenToScreenColorExpand techniques.
428     */
429
430    w += skipleft;
431    x -= skipleft;
432    wc = pApm->ScratchMemSize * 8;
433    wrd = (w + 31) >> 5;
434    wr = wrd << 5;
435    nc = wc / wr;
436    if (nc > h)
437	nc = h;
438    if (wr / 8 > srcwidth)
439	beCareful = TRUE;
440    else
441	beCareful = FALSE;
442    srcwidth -= wr / 8;
443
444    if (skipleft || w != wr) {
445	apmClip = TRUE;
446	A(WaitForFifo)(pApm, 3);
447	SETCLIP_LEFTTOP(x + skipleft, y);
448	SETCLIP_RIGHTBOT(x + w - 1, y + h - 1);
449	SETCLIP_CTRL(1);
450    }
451    else if (pApm->apmClip) {
452	A(WaitForFifo)(pApm, 1);
453	SETCLIP_CTRL(0);
454    }
455    pApm->apmClip = FALSE;
456
457    A(SetupForScreenToScreenColorExpandFill)(pScrn, fg, bg, rop, planemask);
458#ifdef FASTER
459    A(WaitForFifo)(pApm, 2);
460    if (pApm->apmTransparency)
461    SETDEC(DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
462        DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
463        DEC_SOURCE_CONTIG | DEC_SOURCE_TRANSPARENCY | pApm->CurrentLayout.Setup_DEC);
464    else
465    SETDEC(DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
466        DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
467        DEC_SOURCE_CONTIG | pApm->CurrentLayout.Setup_DEC);
468#else
469    A(WaitForFifo)(pApm, 1);
470    c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
471        DEC_START | DEC_DEST_UPD_BLCORNER | DEC_SOURCE_LINEAR |
472        DEC_SOURCE_CONTIG | pApm->CurrentLayout.Setup_DEC;
473    if (pApm->apmTransparency)
474      c |= DEC_SOURCE_TRANSPARENCY;
475#endif
476
477    SETDESTXY(x, y);
478
479    if (!beCareful || h % nc > 3 || (w > 16 && h % nc)) {
480#ifndef FASTER
481	if (h / nc)
482	    SETWIDTHHEIGHT(wr, nc);
483#endif
484	for (n = h / nc; n-- > 0; ) {
485	    int i, j;
486
487	    if (pApm->ScratchMemPtr + nc * wrd * 4 < pApm->ScratchMemEnd) {
488#define		d	((memType)dstPtr - (memType)pApm->FbBase)
489		A(WaitForFifo)(pApm, 1);
490		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
491		switch(pApm->CurrentLayout.bitsPerPixel) {
492		case 8: case 24:
493		    SETSOURCEOFF((d & 0xFFF000) << 4 |
494				(d & 0xFFF));
495		    break;
496		case 16:
497		    SETSOURCEOFF((d & 0xFFE000) << 3 |
498				((d & 0x1FFE) >> 1));
499		    break;
500		case 32:
501		    SETSOURCEOFF((d & 0xFFC000) << 2 |
502				((d & 0x3FFC) >> 2));
503		    break;
504		}
505#undef		d
506	    }
507	    else {
508		(*pApm->AccelInfoRec->Sync)(pScrn);
509		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
510		SETSOURCEOFF(pApm->ScratchMem);
511	    }
512	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * nc) + 4)
513	      & ~(memType)7;
514	    for (i = nc; i-- > 0; ) {
515		for (j = wrd; j-- > 0; ) {
516		    *dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
517		    src += 4;
518		}
519		src += srcwidth;
520	    }
521	    A(WaitForFifo)(pApm, 1);
522#ifdef FASTER
523	    SETWIDTHHEIGHT(wr, nc);
524#else
525	    SETDEC(c);
526#endif
527	}
528    }
529    else {
530#ifndef FASTER
531	if (h / nc)
532	    SETWIDTHHEIGHT(wr, nc);
533#endif
534	for (n = h / nc; n-- > 0; ) {
535	    int i, j;
536
537	    if (pApm->ScratchMemPtr + nc * wrd * 4 < pApm->ScratchMemEnd) {
538#define		d	((memType)dstPtr - (memType)pApm->FbBase)
539		A(WaitForFifo)(pApm, 1);
540		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
541		switch(pApm->CurrentLayout.bitsPerPixel) {
542		case 8: case 24:
543		    SETSOURCEOFF((d & 0xFFF000) << 4 |
544				(d & 0xFFF));
545		    break;
546		case 16:
547		    SETSOURCEOFF((d & 0xFFE000) << 3 |
548				((d & 0x1FFE) >> 1));
549		    break;
550		case 32:
551		    SETSOURCEOFF((d & 0xFFC000) << 2 |
552				((d & 0x3FFC) >> 2));
553		    break;
554		}
555#undef		d
556	    }
557	    else {
558		(*pApm->AccelInfoRec->Sync)(pScrn);
559		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
560		SETSOURCEOFF(pApm->ScratchMem);
561	    }
562	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * nc * 4) + 4) & ~7;
563	    for (i = nc; i-- > 0; ) {
564		for (j = wrd; j-- > 0; ) {
565		    if (i || j || n)
566			*dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
567		    else if (srcwidth > -8) {
568			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[2]];
569			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[1]];
570			((CARD8 *)dstPtr)[2] = byte_reversed[((CARD8 *)src)[0]];
571			dstPtr = (CARD32 *)(3 + (CARD8 *)dstPtr);
572		    }
573		    else if (srcwidth > -16) {
574			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[1]];
575			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[0]];
576			dstPtr = (CARD32 *)(2 + (CARD8 *)dstPtr);
577		    }
578		    else {
579			*(CARD8 *)dstPtr = byte_reversed[*(CARD8 *)src];
580			dstPtr = (CARD32 *)(1 + (CARD8 *)dstPtr);
581		    }
582		    src += 4;
583		}
584		src += srcwidth;
585	    }
586	    A(WaitForFifo)(pApm, 1);
587#ifdef FASTER
588	    SETWIDTHHEIGHT(wr, nc);
589#else
590	    SETDEC(c);
591#endif
592	}
593    }
594
595    /*
596     * Same thing for the remnant
597     */
598    UPDATEDEST(x, y + h + 1);
599    h %= nc;
600    if (h) {
601	if (!beCareful) {
602	    int i, j;
603
604#ifndef FASTER
605	    SETWIDTHHEIGHT(wr, h);
606#endif
607	    if (pApm->ScratchMemPtr + h * wrd * 4 < pApm->ScratchMemEnd) {
608#define		d	((memType)dstPtr - (memType)pApm->FbBase)
609		A(WaitForFifo)(pApm, 1);
610		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
611		switch(pApm->CurrentLayout.bitsPerPixel) {
612		case 8: case 24:
613		    SETSOURCEOFF((d & 0xFFF000) << 4 |
614				(d & 0xFFF));
615		    break;
616		case 16:
617		    SETSOURCEOFF((d & 0xFFE000) << 3 |
618				((d & 0x1FFE) >> 1));
619		    break;
620		case 32:
621		    SETSOURCEOFF((d & 0xFFC000) << 2 |
622				((d & 0x3FFC) >> 2));
623		    break;
624		}
625#undef		d
626	    }
627	    else {
628		(*pApm->AccelInfoRec->Sync)(pScrn);
629		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
630		SETSOURCEOFF(pApm->ScratchMem);
631	    }
632	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * h) + 4) & ~7;
633	    for (i = h; i-- > 0; ) {
634		for (j = wrd; j-- > 0; ) {
635		    *dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
636		    src += 4;
637		}
638		src += srcwidth;
639	    }
640	    A(WaitForFifo)(pApm, 1);
641#ifdef FASTER
642	    SETWIDTHHEIGHT(wr, h);
643#else
644	    SETDEC(c);
645#endif
646	}
647	else {
648	    int i, j;
649
650#ifndef FASTER
651	    SETWIDTHHEIGHT(w, h);
652#endif
653	    if (pApm->ScratchMemPtr + h * wrd * 4 < pApm->ScratchMemEnd) {
654#define		d	((memType)dstPtr - (memType)pApm->FbBase)
655		A(WaitForFifo)(pApm, 1);
656		dstPtr = (CARD32 *)pApm->ScratchMemPtr;
657		switch(pApm->CurrentLayout.bitsPerPixel) {
658		case 8: case 24:
659		    SETSOURCEOFF((d & 0xFFF000) << 4 |
660				(d & 0xFFF));
661		    break;
662		case 16:
663		    SETSOURCEOFF((d & 0xFFE000) << 3 |
664				((d & 0x1FFE) >> 1));
665		    break;
666		case 32:
667		    SETSOURCEOFF((d & 0xFFC000) << 2 |
668				((d & 0x3FFC) >> 2));
669		    break;
670		}
671#undef		d
672	    }
673	    else {
674		(*pApm->AccelInfoRec->Sync)(pScrn);
675		dstPtr = (CARD32 *)pApm->ScratchMemOffset;
676		SETSOURCEOFF(pApm->ScratchMem);
677	    }
678	    pApm->ScratchMemPtr = ((memType)(dstPtr + wrd * h) + 4) & ~7;
679	    for (i = h; i-- > 0; ) {
680		for (j = wrd; j-- > 0; ) {
681		    if (i || j)
682			*dstPtr++ = XAAReverseBitOrder(*(CARD32 *)src);
683		    else if (srcwidth > -8) {
684			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[2]];
685			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[1]];
686			((CARD8 *)dstPtr)[2] = byte_reversed[((CARD8 *)src)[0]];
687			dstPtr = (CARD32 *)(3 + (CARD8 *)dstPtr);
688		    }
689		    else if (srcwidth > -16) {
690			((CARD8 *)dstPtr)[0] = byte_reversed[((CARD8 *)src)[1]];
691			((CARD8 *)dstPtr)[1] = byte_reversed[((CARD8 *)src)[0]];
692			dstPtr = (CARD32 *)(2 + (CARD8 *)dstPtr);
693		    }
694		    else {
695			*(CARD8 *)dstPtr = byte_reversed[*(CARD8 *)src];
696			dstPtr = (CARD32 *)(1 + (CARD8 *)dstPtr);
697		    }
698		    src += 4;
699		}
700		src += srcwidth;
701	    }
702	    A(WaitForFifo)(pApm, 1);
703#ifdef FASTER
704	    SETWIDTHHEIGHT(w, h);
705#else
706	    SETDEC(c);
707#endif
708	}
709    }
710    pApm->apmClip = apmClip;
711}
712
713static void
714A(TEGlyphRenderer)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
715		    int skipleft, int startline,
716		    unsigned int **glyphs, int glyphWidth,
717		    int fg, int bg, int rop, unsigned planemask)
718{
719    CARD32 *base, *base0;
720    GlyphScanlineFuncPtr GlyphFunc;
721    static GlyphScanlineFuncPtr *GlyphTab = NULL;
722    int w2, h2, dwords;
723
724    if (!GlyphTab) GlyphTab = XAAGetGlyphScanlineFuncLSBFirst();
725    GlyphFunc = GlyphTab[glyphWidth - 1];
726
727    w2 = w + skipleft;
728    h2 = h;
729    dwords = (w2 + 31) >> 5;
730    dwords <<= 2;
731
732    base0 = base = (CARD32*)xalloc(dwords * h);
733    if (!base)
734	return;		/* Should not happen : it's rather small... */
735
736    while(h--) {
737	base = (*GlyphFunc)(base, glyphs, startline++, w2, glyphWidth);
738    }
739
740    A(WriteBitmap)(pScrn, x, y, w, h2, (unsigned char *)base0, dwords,
741		    skipleft, fg, bg, rop, planemask);
742
743    xfree(base0);
744}
745
746static void A(SetupForMono8x8PatternFill)(ScrnInfoPtr pScrn, int patx, int paty,
747				          int fg, int bg, int rop,
748				          unsigned int planemask)
749{
750    APMDECL(pScrn);
751
752    DPRINTNAME(SetupForMono8x8PatternFill);
753    pApm->apmTransparency = (pApm->Chipset >= AT3D) && (bg == -1);
754    pApm->Bg8x8 = bg;
755    pApm->Fg8x8 = fg;
756    pApm->rop = apmROP[rop];
757    A(WaitForFifo)(pApm, 3 + pApm->apmClip);
758    if (bg == -1)
759	SETBACKGROUNDCOLOR(fg + 1);
760    else
761	SETBACKGROUNDCOLOR(bg);
762    SETFOREGROUNDCOLOR(fg);
763    if (pApm->Chipset >= AT3D)
764	SETROP(apmROP[rop] & 0xF0);
765    else
766	SETROP((apmROP[rop] & 0xF0) | 0x0A);
767    if (pApm->apmClip) {
768	SETCLIP_CTRL(0);
769	pApm->apmClip = FALSE;
770    }
771}
772
773static void A(SubsequentMono8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
774					        int paty, int x, int y,
775					        int w, int h)
776{
777    APMDECL(pScrn);
778
779    DPRINTNAME(SubsequentMono8x8PatternFillRect);
780    SETDESTXY(x, y);
781    UPDATEDEST(x, y + h + 1);
782    A(WaitForFifo)(pApm, 6);
783    if (pApm->Chipset == AT24 && pApm->Bg8x8 != -1) {
784	SETROP(pApm->rop);
785	SETFOREGROUNDCOLOR(pApm->Bg8x8);
786#ifdef FASTER
787	SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
788		DEC_DEST_XY | DEC_QUICKSTART_ONDIMX);
789	SETWIDTHHEIGHT(w, h);
790#else
791	SETWIDTHHEIGHT(w, h);
792	SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
793		DEC_DEST_XY | DEC_START);
794#endif
795	A(WaitForFifo)(pApm, 6);
796	SETROP((pApm->rop & 0xF0) | 0x0A);
797	SETFOREGROUNDCOLOR(pApm->Fg8x8);
798    }
799    SETPATTERN(patx, paty);
800#ifdef FASTER
801    SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
802	    DEC_DEST_XY | DEC_PATTERN_88_1bMONO | DEC_DEST_UPD_TRCORNER |
803	    (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) |
804	    DEC_QUICKSTART_ONDIMX);
805    SETWIDTHHEIGHT(w, h);
806#else
807    SETWIDTHHEIGHT(w, h);
808    SETDEC(pApm->CurrentLayout.Setup_DEC | ((h == 1) ? DEC_OP_STRIP : DEC_OP_RECT) |
809	    DEC_DEST_XY | DEC_PATTERN_88_1bMONO | DEC_DEST_UPD_TRCORNER |
810	    (pApm->apmTransparency ? DEC_SOURCE_TRANSPARENCY : 0) |
811	    DEC_START);
812#endif
813}
814
815#if 0
816static void
817A(SetupForCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int fg, int bg,
818					int rop, unsigned int planemask)
819{
820  APMDECL(pScrn);
821
822  DPRINTNAME(SetupForCPUToScreenColorExpandFill);
823  if (bg == -1)
824  {
825#ifndef FASTER
826    pApm->apmTransparency = TRUE;
827    A(WaitForFifo)(pApm, 3);
828#else
829    A(WaitForFifo)(pApm, 4);
830    SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
831      DEC_SOURCE_TRANSPARENCY | DEC_SOURCE_MONOCHROME | DEC_QUICKSTART_ONDIMX |
832      DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC);
833#endif
834    SETFOREGROUNDCOLOR(fg);
835    SETBACKGROUNDCOLOR(fg+1);
836  }
837  else
838  {
839#ifndef FASTER
840    pApm->apmTransparency = FALSE;
841    A(WaitForFifo)(pApm, 3);
842#else
843    A(WaitForFifo)(pApm, 4);
844    SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
845	   DEC_DEST_UPD_TRCORNER | DEC_SOURCE_MONOCHROME |
846	   DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
847#endif
848    SETFOREGROUNDCOLOR(fg);
849    SETBACKGROUNDCOLOR(bg);
850  }
851  SETROP(apmROP[rop]);
852}
853
854static void
855A(SubsequentCPUToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y,
856					int w, int h, int skipleft)
857{
858  APMDECL(pScrn);
859#ifndef FASTER
860  u32 c;
861#endif
862
863  DPRINTNAME(SubsequentCPUToScreenColorExpandFill);
864#ifndef FASTER
865  c = DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
866      DEC_SOURCE_MONOCHROME | DEC_START | DEC_DEST_UPD_TRCORNER |
867      pApm->CurrentLayout.Setup_DEC;
868
869  if (pApm->apmTransparency)
870    c |= DEC_SOURCE_TRANSPARENCY;
871
872  A(WaitForFifo)(pApm, 7);
873#else
874  A(WaitForFifo)(pApm, 6);
875#endif
876
877  SETCLIP_LEFTTOP(x+skipleft, y);
878  SETCLIP_RIGHTBOT(x+w-1, y+h-1);
879  SETCLIP_CTRL(0x01);
880  pApm->apmClip = TRUE;
881  SETSOURCEX(0); /* According to manual, it just has to be zero */
882  SETDESTXY(x, y);
883  SETWIDTHHEIGHT((w + 31) & ~31, h);
884  UPDATEDEST(x + ((w + 31) & ~31), y);
885
886#ifndef FASTER
887  SETDEC(c);
888#endif
889}
890#endif
891
892static void
893A(SetupForImageWrite)(ScrnInfoPtr pScrn, int rop, unsigned int planemask,
894		      int trans_color, int bpp, int depth)
895{
896  APMDECL(pScrn);
897
898  DPRINTNAME(SetupForImageWrite);
899  if (trans_color != -1)
900  {
901#ifndef FASTER
902    pApm->apmTransparency = TRUE;
903    A(WaitForFifo)(pApm, 3);
904#else
905    A(WaitForFifo)(pApm, 4);
906    SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
907	  DEC_SOURCE_TRANSPARENCY | DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
908#endif
909    SETBACKGROUNDCOLOR(trans_color);
910  }
911  else {
912#ifndef FASTER
913    pApm->apmTransparency = FALSE;
914    A(WaitForFifo)(pApm, 2);
915#else
916    A(WaitForFifo)(pApm, 3);
917    SETDEC(DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
918	  DEC_QUICKSTART_ONDIMX | pApm->CurrentLayout.Setup_DEC);
919#endif
920  }
921
922  SETROP(apmROP[rop]);
923}
924
925static void
926A(SubsequentImageWriteRect)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
927			    int skipleft)
928{
929  APMDECL(pScrn);
930#ifndef FASTER
931  u32 c;
932#endif
933
934  DPRINTNAME(SubsequentImageWriteRect);
935#ifndef FASTER
936  c = DEC_OP_HOSTBLT_HOST2SCREEN | DEC_SOURCE_LINEAR | DEC_SOURCE_CONTIG |
937      DEC_START | pApm->CurrentLayout.Setup_DEC;
938
939  if (pApm->apmTransparency)
940    c |= DEC_SOURCE_TRANSPARENCY;
941
942  if (pApm->Chipset >= AT24)
943      A(WaitForFifo)(pApm, 7);
944  else
945      A(WaitForFifo)(pApm, 3);
946#else
947  if (pApm->Chipset >= AT24)
948      A(WaitForFifo)(pApm, 6);
949  else
950      A(WaitForFifo)(pApm, 3);
951#endif
952
953  SETCLIP_LEFTTOP(x+skipleft, y);
954  SETCLIP_RIGHTBOT(x+w-1, y+h-1);
955  SETCLIP_CTRL(0x01);
956  pApm->apmClip = TRUE;
957  if (pApm->Chipset < AT24)
958      A(WaitForFifo)(pApm, 4);
959  SETSOURCEX(0); /* According to manual, it just has to be zero */
960  SETDESTXY(x, y);
961  SETWIDTHHEIGHT((w + 3) & ~3, h);
962
963#ifndef FASTER
964  SETDEC(c);
965#endif
966}
967
968static void
969A(SubsequentScreenToScreenColorExpandFill)(ScrnInfoPtr pScrn, int x, int y,
970					   int w, int h, int srcx, int srcy,
971					   int offset)
972{
973  APMDECL(pScrn);
974  u32 c;
975
976  DPRINTNAME(SubsequentScreenToScreenColorExpandFill);
977#ifdef FASTER
978  c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
979      DEC_QUICKSTART_ONDIMX | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC;
980#else
981  c = DEC_OP_BLT | DEC_DIR_X_POS | DEC_DIR_Y_POS | DEC_SOURCE_MONOCHROME |
982      DEC_START | DEC_DEST_UPD_TRCORNER | pApm->CurrentLayout.Setup_DEC;
983#endif
984
985  if (pApm->apmTransparency)
986    c |= DEC_SOURCE_TRANSPARENCY;
987
988  if (srcy >= pApm->CurrentLayout.Scanlines) {
989      struct ApmStippleCacheRec *pCache;
990      CARD32	dist;
991
992      /*
993       * Offscreen linear stipple
994       */
995      pCache = &pApm->apmCache[srcy / pApm->CurrentLayout.Scanlines - 1];
996      if (w != pCache->apmStippleCache.w * pApm->CurrentLayout.bitsPerPixel) {
997	  A(WaitForFifo)(pApm, 3);
998	  SETCLIP_LEFTTOP(x, y);
999	  SETCLIP_RIGHTBOT(x + w - 1, y + h - 1);
1000	  SETCLIP_CTRL(0x01);
1001	  pApm->apmClip = TRUE;
1002	  w = pCache->apmStippleCache.w * pApm->CurrentLayout.bitsPerPixel;
1003	  x -= srcx - pCache->apmStippleCache.x + offset;
1004	  srcx = (srcy - pCache->apmStippleCache.y) & 7;
1005	  srcy -= srcx;
1006	  y -= srcx;
1007	  h += srcx;
1008	  srcx = pCache->apmStippleCache.x;
1009      }
1010      else if (pApm->apmClip) {
1011	  A(WaitForFifo)(pApm, 1);
1012	  SETCLIP_CTRL(0x00);
1013	  pApm->apmClip = FALSE;
1014      }
1015      srcx += (srcy - pCache->apmStippleCache.y) * pCache->apmStippleCache.w;
1016      srcy = pCache->apmStippleCache.y % pApm->CurrentLayout.Scanlines;
1017      dist = srcx + srcy * pApm->CurrentLayout.displayWidth;
1018      srcx = dist & 0xFFF;
1019      srcy = dist >> 12;
1020      c |= DEC_SOURCE_CONTIG | DEC_SOURCE_LINEAR;
1021  }
1022  else if (offset) {
1023      A(WaitForFifo)(pApm, 3);
1024      SETCLIP_LEFTTOP(x, y);
1025      SETCLIP_RIGHTBOT(x + w, y + h);
1026      SETCLIP_CTRL(0x01);
1027      pApm->apmClip = TRUE;
1028      w += offset;
1029      x -= offset;
1030  }
1031  else if (pApm->apmClip) {
1032      A(WaitForFifo)(pApm, 1);
1033      SETCLIP_CTRL(0x00);
1034      pApm->apmClip = FALSE;
1035  }
1036
1037  A(WaitForFifo)(pApm, 4);
1038
1039  SETSOURCEXY(srcx, srcy);
1040  SETDESTXY(x, y);
1041
1042#ifdef FASTER
1043  SETDEC(c);
1044  SETWIDTHHEIGHT(w, h);
1045#else
1046  SETWIDTHHEIGHT(w, h);
1047  SETDEC(c);
1048#endif
1049  UPDATEDEST(x + w + 1, h);
1050}
1051
1052static void
1053A(SubsequentSolidBresenhamLine)(ScrnInfoPtr pScrn, int x1, int y1, int e1,
1054				int e2, int err, int length, int octant)
1055{
1056  APMDECL(pScrn);
1057#ifdef FASTER
1058  u32 c = DEC_QUICKSTART_ONDIMX | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX |
1059	  pApm->CurrentLayout.Setup_DEC;
1060#else
1061  u32 c = DEC_START | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX | pApm->CurrentLayout.Setup_DEC;
1062#endif
1063  int	tmp;
1064
1065  DPRINTNAME(SubsequentSolidBresenhamLine);
1066
1067  A(WaitForFifo)(pApm, 5);
1068  SETDESTXY(x1,y1);
1069  SETDDA_ERRORTERM(err);
1070  SETDDA_ADSTEP(e1, e2);
1071
1072  if (octant & YMAJOR) {
1073    c |= DEC_MAJORAXIS_Y;
1074    tmp = e1; e1 = e2; e2 = tmp;
1075  }
1076  else
1077    c |= DEC_MAJORAXIS_X;
1078
1079  if (octant & XDECREASING) {
1080    c |= DEC_DIR_X_NEG;
1081    e1 = -e1;
1082  }
1083  else
1084    c |= DEC_DIR_X_POS;
1085
1086  if (octant & YDECREASING) {
1087    c |= DEC_DIR_Y_NEG;
1088    e2 = -e2;
1089  }
1090  else
1091    c |= DEC_DIR_Y_POS;
1092
1093#ifdef FASTER
1094  SETDEC(c);
1095  SETWIDTH(length);
1096#else
1097  SETWIDTH(length);
1098  SETDEC(c);
1099#endif
1100
1101  if (octant & YMAJOR)
1102    UPDATEDEST(x1 + e1 / 2, y1 + e2 / 2);
1103  else
1104    UPDATEDEST(x1 + e2 / 2, y1 + e1 / 2);
1105  if (pApm->apmClip)
1106  {
1107    pApm->apmClip = FALSE;
1108    A(WaitForFifo)(pApm, 1);
1109    SETCLIP_CTRL(0);
1110  }
1111}
1112
1113static void
1114A(SubsequentSolidBresenhamLine6422)(ScrnInfoPtr pScrn, int x1, int y1, int e1,
1115				int e2, int err, int length, int octant)
1116{
1117  APMDECL(pScrn);
1118#ifdef FASTER
1119  u32 c = DEC_QUICKSTART_ONDIMX | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX |
1120	  pApm->CurrentLayout.Setup_DEC;
1121#else
1122  u32 c = DEC_START | DEC_OP_VECT_ENDP | DEC_DEST_UPD_LASTPIX | pApm->CurrentLayout.Setup_DEC;
1123#endif
1124  int	tmp;
1125
1126  DPRINTNAME(SubsequentSolidBresenhamLine6422);
1127
1128  A(WaitForFifo)(pApm, 1);
1129  SETDESTXY(x1,y1);
1130  A(WaitForFifo)(pApm, 4);
1131  SETDDA_ERRORTERM(err);
1132  SETDDA_ADSTEP(e1, e2);
1133
1134  if (octant & YMAJOR) {
1135    c |= DEC_MAJORAXIS_Y;
1136    tmp = e1; e1 = e2; e2 = tmp;
1137  }
1138  else
1139    c |= DEC_MAJORAXIS_X;
1140
1141  if (octant & XDECREASING) {
1142    c |= DEC_DIR_X_NEG;
1143    e1 = -e1;
1144  }
1145  else
1146    c |= DEC_DIR_X_POS;
1147
1148  if (octant & YDECREASING) {
1149    c |= DEC_DIR_Y_NEG;
1150    e2 = -e2;
1151  }
1152  else
1153    c |= DEC_DIR_Y_POS;
1154
1155#ifdef FASTER
1156  SETDEC(c);
1157  SETWIDTH(length);
1158#else
1159  SETWIDTH(length);
1160  SETDEC(c);
1161#endif
1162
1163  if (octant & YMAJOR)
1164    UPDATEDEST(x1 + e1 / 2, y1 + e2 / 2);
1165  else
1166    UPDATEDEST(x1 + e2 / 2, y1 + e1 / 2);
1167  if (pApm->apmClip)
1168  {
1169    pApm->apmClip = FALSE;
1170    A(WaitForFifo)(pApm, 1);
1171    SETCLIP_CTRL(0);
1172  }
1173}
1174
1175static void
1176A(SetClippingRectangle)(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
1177{
1178  APMDECL(pScrn);
1179
1180  DPRINTNAME(SetClippingRectangle);
1181  A(WaitForFifo)(pApm, 3);
1182  SETCLIP_LEFTTOP(x1,y1);
1183  SETCLIP_RIGHTBOT(x2,y2);
1184  SETCLIP_CTRL(0x01);
1185  pApm->apmClip = TRUE;
1186}
1187
1188static void
1189A(SyncBlt)(ApmPtr pApm)
1190{
1191    int again = (pApm->Chipset == AP6422);
1192
1193    do {
1194       while (!(STATUS() & STATUS_HOSTBLTBUSY))
1195	   ;
1196    }
1197    while (again--);	/* See remark in Sync6422 */
1198}
1199static void
1200A(WritePixmap)(ScrnInfoPtr pScrn, int x, int y, int w, int h,
1201	       unsigned char *src, int srcwidth, int rop,
1202	       unsigned int planemask, int trans, int bpp, int depth)
1203{
1204    APMDECL(pScrn);
1205    int dwords, skipleft, Bpp = bpp >> 3;
1206    Bool beCareful = FALSE;
1207    unsigned char *dst = ((unsigned char *)pApm->FbBase) + x * Bpp + y * pApm->CurrentLayout.bytesPerScanline;
1208    int PlusOne = 0, mask, count;
1209
1210    DPRINTNAME(WritePixmap);
1211    if (rop == GXnoop)
1212	return;
1213    /*
1214     * The function seems to crash more than it feels good. I hope that a
1215     * good sync will help. This sync is anyway needed for direct write.
1216     */
1217    (*pApm->AccelInfoRec->Sync)(pScrn);
1218    /*
1219     * First the fast case : source and dest have same alignment. Doc says
1220     * it's faster to do it here, which may be true since one has to read
1221     * the chip when CPU to screen-ing.
1222     */
1223    if ((skipleft = (long)src & 3L) == ((long)dst & 3L) && rop == GXcopy) {
1224	int skipright;
1225
1226	if (skipleft)
1227	    skipleft = 4 - skipleft;
1228	dwords = (skipright = w * Bpp - skipleft) >> 2;
1229	skipright %= 4;
1230	if (!skipleft && !skipright)
1231	    while (h-- > 0) {
1232		CARD32 *src2 = (CARD32 *)src;
1233		CARD32 *dst2 = (CARD32 *)dst;
1234
1235		for (count = dwords; count-- > 0; )
1236		    *dst2++ = *src2++;
1237		src += srcwidth;
1238		dst += pApm->CurrentLayout.bytesPerScanline;
1239	    }
1240	else if (!skipleft)
1241	    while (h-- > 0) {
1242		CARD32 *src2 = (CARD32 *)src;
1243		CARD32 *dst2 = (CARD32 *)dst;
1244
1245		for (count = dwords; count-- > 0; )
1246		    *dst2++ = *src2++;
1247		for (count = skipright; count-- > 0; )
1248		    ((char *)dst2)[count] = ((char *)src2)[count];
1249		src += srcwidth;
1250		dst += pApm->CurrentLayout.bytesPerScanline;
1251	    }
1252	else if (!skipright)
1253	    while (h-- > 0) {
1254		CARD32 *src2 = (CARD32 *)(src + skipleft);
1255		CARD32 *dst2 = (CARD32 *)(dst + skipleft);
1256
1257		for (count = skipleft; count-- > 0; )
1258		    dst[count] = src[count];
1259		for (count = dwords; count-- > 0; )
1260		    *dst2++ = *src2++;
1261		src += srcwidth;
1262		dst += pApm->CurrentLayout.bytesPerScanline;
1263	    }
1264	else
1265	    while (h-- > 0) {
1266		CARD32 *src2 = (CARD32 *)(src + skipleft);
1267		CARD32 *dst2 = (CARD32 *)(dst + skipleft);
1268
1269		for (count = skipleft; count-- > 0; )
1270		    dst[count] = src[count];
1271		for (count = dwords; count-- > 0; )
1272		    *dst2++ = *src2++;
1273		for (count = skipright; count-- > 0; )
1274		    ((char *)dst2)[count] = ((char *)src2)[count];
1275		src += srcwidth;
1276		dst += pApm->CurrentLayout.bytesPerScanline;
1277	    }
1278
1279	return;
1280    }
1281
1282    if (skipleft) {
1283	if (Bpp == 3)
1284	   skipleft = 4 - skipleft;
1285	else
1286	   skipleft /= Bpp;
1287
1288	if (x < skipleft) {
1289	   skipleft = 0;
1290	   beCareful = TRUE;
1291	   goto BAD_ALIGNMENT;
1292	}
1293
1294	x -= skipleft;
1295	w += skipleft;
1296
1297	if (Bpp == 3)
1298	   src -= 3 * skipleft;
1299	else   /* is this Alpha friendly ? */
1300	   src = (unsigned char*)((long)src & ~0x03L);
1301    }
1302
1303BAD_ALIGNMENT:
1304
1305    dwords = ((w * Bpp) + 3) >> 2;
1306    mask = (pApm->CurrentLayout.bitsPerPixel / 8) - 1;
1307
1308    if (dwords & mask) {
1309	/*
1310	 * Experimental...
1311	 * It seems the AT3D needs a padding of scanline to a multiple of
1312	 * 4 pixels, not only bytes.
1313	 */
1314	PlusOne = mask - (dwords & mask) + 1;
1315    }
1316
1317    A(SetupForImageWrite)(pScrn, rop, planemask, trans, bpp, depth);
1318    A(SubsequentImageWriteRect)(pScrn, x, y, w, h, skipleft);
1319
1320    if (beCareful) {
1321	/* in cases with bad alignment we have to be careful not
1322	   to read beyond the end of the source */
1323	if (((x * Bpp) + (dwords << 2)) > srcwidth) h--;
1324	else beCareful = FALSE;
1325    }
1326
1327    srcwidth -= (dwords << 2);
1328
1329    while (h--) {
1330	for (count = dwords; count-- > 0; ) {
1331	    A(SyncBlt)(pApm);
1332	    *(CARD32*)pApm->BltMap = *(CARD32*)src;
1333	    src += 4;
1334	}
1335	src += srcwidth;
1336	for (count = PlusOne; count-- > 0; ) {
1337	    int	status;
1338
1339	    while (!((status = STATUS()) & STATUS_HOSTBLTBUSY))
1340		if (!(status & STATUS_ENGINEBUSY))
1341		    break;
1342	    if (pApm->Chipset == AP6422)	/* See remark in Sync6422 */
1343		while (!((status = STATUS()) & STATUS_HOSTBLTBUSY))
1344		    if (!(status & STATUS_ENGINEBUSY))
1345			break;
1346	    if (status & STATUS_ENGINEBUSY)
1347		*(CARD32*)pApm->BltMap = 0x00000000;
1348	}
1349    }
1350    if (beCareful) {
1351       int shift = ((long)src & 0x03L) << 3;
1352
1353       if (--dwords) {
1354	    for (count = dwords >> 2; count-- > 0; ) {
1355		A(SyncBlt)(pApm);
1356		*(CARD32*)pApm->BltMap = *(CARD32*)src;
1357		src += 4;
1358	    }
1359       }
1360       A(SyncBlt)(pApm);
1361       *((CARD32*)pApm->BltMap) = *((CARD32*)src) >> shift;
1362    }
1363
1364    pApm->apmClip = FALSE;
1365    A(WaitForFifo)(pApm, 1);
1366    SETCLIP_CTRL(0);
1367}
1368
1369static void
1370A(FillImageWriteRects)(ScrnInfoPtr pScrn, int rop, unsigned int planemask,
1371			int nBox, BoxPtr pBox, int xorg, int yorg,
1372			PixmapPtr pPix)
1373{
1374    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn);
1375    int x, y, phaseY, phaseX, height, width, blit_w;
1376    int pHeight = pPix->drawable.height;
1377    int pWidth = pPix->drawable.width;
1378    int depth = pPix->drawable.depth;
1379    int bpp = pPix->drawable.bitsPerPixel;
1380    unsigned char *pSrc;
1381    int srcwidth = pPix->devKind;
1382
1383    while(nBox--) {
1384	x = pBox->x1;
1385	y = pBox->y1;
1386	phaseY = (pBox->y1 - yorg) % pHeight;
1387	if(phaseY < 0) phaseY += pHeight;
1388	phaseX = (x - xorg) % pWidth;
1389	pSrc = (unsigned char *)pPix->devPrivate.ptr +
1390				    phaseX * pPix->drawable.bitsPerPixel / 8;
1391	if(phaseX < 0) phaseX += pWidth;
1392	height = pBox->y2 - pBox->y1;
1393	width = pBox->x2 - x;
1394
1395	while(1) {
1396	    int		ch = height, cp = phaseY, cy = y;
1397
1398	    blit_w = pWidth - phaseX;
1399	    if(blit_w > width) blit_w = width;
1400
1401	    while (ch > 0) {
1402		int	h = MIN(pHeight - cp, ch);
1403
1404		A(WritePixmap)(pScrn, x, cy, blit_w, h, pSrc + cp * srcwidth,
1405				srcwidth, rop, planemask, FALSE, bpp, depth);
1406		cy += h;
1407		ch -= h;
1408		cp = 0;
1409	    }
1410
1411	    width -= blit_w;
1412	    if(!width) break;
1413	    x += blit_w;
1414	    phaseX = (phaseX + blit_w) % pWidth;
1415	}
1416	pBox++;
1417    }
1418
1419    SET_SYNC_FLAG(infoRec);
1420}
1421
1422static void A(SetupForColor8x8PatternFill)(ScrnInfoPtr pScrn,int patx,int paty,
1423				           int rop, unsigned int planemask,
1424					   int transparency_color)
1425{
1426    APMDECL(pScrn);
1427
1428    DPRINTNAME(SetupForColor8x8PatternFillRect);
1429    if (transparency_color != -1) {
1430#ifndef FASTER
1431	pApm->apmTransparency = TRUE;
1432	A(WaitForFifo)(pApm, 2 + pApm->apmClip);
1433#else
1434	A(WaitForFifo)(pApm, 3 + pApm->apmClip);
1435	SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
1436	    DEC_DEST_XY | DEC_PATTERN_88_8bCOLOR | DEC_SOURCE_TRANSPARENCY |
1437	    DEC_QUICKSTART_ONDIMX);
1438#endif
1439	SETBACKGROUNDCOLOR(transparency_color);
1440    }
1441    else {
1442#ifndef FASTER
1443	pApm->apmTransparency = FALSE;
1444	A(WaitForFifo)(pApm, 1 + pApm->apmClip);
1445#else
1446	A(WaitForFifo)(pApm, 2 + pApm->apmClip);
1447	SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
1448	    DEC_DEST_XY | DEC_PATTERN_88_8bCOLOR | DEC_QUICKSTART_ONDIMX);
1449#endif
1450    }
1451    if (pApm->apmClip) {
1452	SETCLIP_CTRL(0);
1453	pApm->apmClip = FALSE;
1454    }
1455    SETROP(apmROP[rop]);
1456}
1457
1458static void A(SubsequentColor8x8PatternFillRect)(ScrnInfoPtr pScrn, int patx,
1459					         int paty, int x, int y,
1460					         int w, int h)
1461{
1462    APMDECL(pScrn);
1463
1464    DPRINTNAME(SubsequentColor8x8PatternFillRect);
1465#ifndef FASTER
1466    A(WaitForFifo)(pApm, 5);
1467#else
1468    A(WaitForFifo)(pApm, 4);
1469#endif
1470    SETSOURCEXY(patx, paty);
1471    SETDESTXY(x, y);
1472    SETWIDTHHEIGHT(w, h);
1473    UPDATEDEST(x + w + 1, y);
1474#ifndef FASTER
1475    SETDEC(pApm->CurrentLayout.Setup_DEC | DEC_OP_BLT |
1476	    DEC_DEST_XY | (pApm->apmTransparency * DEC_SOURCE_TRANSPARENCY) |
1477	    DEC_PATTERN_88_8bCOLOR | DEC_START);
1478#endif
1479}
1480#endif
1481
1482static void
1483A(Sync)(ScrnInfoPtr pScrn)
1484{
1485  APMDECL(pScrn);
1486  volatile u32 i, stat;
1487
1488  for(i = 0; i < MAXLOOP; i++) {
1489    stat = STATUS();
1490    if ((!(stat & (STATUS_HOSTBLTBUSY | STATUS_ENGINEBUSY))) &&
1491        ((stat & STATUS_FIFO) >= 8))
1492      break;
1493  }
1494  if (i == MAXLOOP) {
1495    unsigned int status = STATUS();
1496
1497    WRXB(0x1FF, 0);
1498    if (!xf86ServerIsExiting())
1499	FatalError("Hung in ApmSync" APM_SUFF_24 APM_SUFF_IOP "(%d) (Status = 0x%08X)\n", pScrn->pScreen->myNum, status);
1500  }
1501  if (pApm->apmClip) {
1502    SETCLIP_CTRL(0);
1503    pApm->apmClip = FALSE;
1504  }
1505}
1506
1507#if PSZ != 24
1508static void
1509A(Sync6422)(ScrnInfoPtr pScrn)
1510{
1511  APMDECL(pScrn);
1512  volatile u32 i, j, stat;
1513
1514  for (j = 0; j < 2; j++) {
1515      /*
1516       * From Henrik Harmsen :
1517       *
1518       * This is a kludge. We can't trust the status register. Don't
1519       * know why... We shouldn't be forced to read the status reg and get
1520       * a correct value more than once...
1521       */
1522      for(i = 0; i < MAXLOOP; i++) {
1523	stat = STATUS();
1524	if ((!(stat & (STATUS_HOSTBLTBUSY | STATUS_ENGINEBUSY))) &&
1525	    ((stat & STATUS_FIFO) >= 4))
1526	  break;
1527      }
1528  }
1529  if (i == MAXLOOP) {
1530    unsigned int status = STATUS();
1531
1532    WRXB(0x1FF, 0);
1533    if (!xf86ServerIsExiting())
1534	FatalError("Hung in ApmSync6422() (Status = 0x%08X)\n", status);
1535  }
1536  if (pApm->apmClip) {
1537    SETCLIP_CTRL(0);
1538    pApm->apmClip = FALSE;
1539  }
1540}
1541#endif
1542#include "apm_video.c"
1543
1544
1545#undef	RDXB
1546#undef	RDXW
1547#undef	RDXL
1548#undef	WRXB
1549#undef	WRXW
1550#undef	WRXL
1551#undef	ApmWriteSeq
1552#define RDXB	RDXB_M
1553#define RDXW	RDXW_M
1554#define RDXL	RDXL_M
1555#define WRXB	WRXB_M
1556#define WRXW	WRXW_M
1557#define WRXL	WRXL_M
1558#define ApmWriteSeq(idx, val)	do { APMVGAB(0x3C4) = (idx); APMVGAB(0x3C5) = (val); break; } while(1)
1559#undef DPRINTNAME
1560#undef A
1561#undef DEPTH
1562#undef PSZ
1563#undef IOP_ACCESS
1564#undef APM_SUFF_24
1565#undef APM_SUFF_IOP
1566