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