tdfx_accel.c revision 880ed95a
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6/* All drivers should typically include these */
7#include "xf86.h"
8#include "xf86_OSproc.h"
9#include "compiler.h"
10
11/* Drivers that need to access the PCI config space directly need this */
12#include "xf86Pci.h"
13
14/* Drivers for PCI hardware need this */
15#include "xf86PciInfo.h"
16
17/* Drivers that use XAA need this */
18#include "xaa.h"
19#include "xaalocal.h"
20#include "xf86fbman.h"
21
22#include "miline.h"
23
24#include "tdfx.h"
25
26#ifdef TDFX_DEBUG_CMDS
27static int cmdCnt=0;
28static int lastAddr=0;
29#endif
30
31static int TDFXROPCvt[] = {0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE,
32			   0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF,
33			   0x00, 0xA0, 0x50, 0xF0, 0x0A, 0xAA, 0x5A, 0xFA,
34			   0x05, 0xA5, 0x55, 0xF5, 0x0F, 0xAF, 0x5F, 0xFF};
35#define ROP_PATTERN_OFFSET 16
36
37static void TDFXSetClippingRectangle(ScrnInfoPtr pScrn, int left, int top,
38				     int right, int bottom);
39static void TDFXDisableClipping(ScrnInfoPtr pScrn);
40static void TDFXSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx,
41					   int paty, int fg, int bg, int rop,
42					   unsigned int planemask);
43static void TDFXSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int patx,
44						 int pay, int x, int y,
45						 int w, int h);
46static void TDFXSetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
47				  unsigned int planemask);
48static void TDFXSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn, int srcx,
49					    int srcy, int dstx, int dsty,
50					    int flags);
51static void TDFXSubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y,
52					   int len, int dir);
53static void TDFXNonTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int n,
54				   NonTEGlyphPtr glyphs, BoxPtr pbox, int fg,
55				   int rop, unsigned int planemask);
56static void TDFXSetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop,
57                                   unsigned int planemask, int length,
58		                   unsigned char *pattern);
59static void TDFXSubsequentDashedTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1,
60                                             int x2, int y2, int flags,
61                                             int phase);
62#ifdef ENABLE_SS_COLOR_EXPAND_FILL
63static void TDFXSetupForScreenToScreenColorExpandFill(ScrnInfoPtr pScrn,
64                                                      int fg, int bg, int rop,
65                                                      unsigned int planemask);
66static void TDFXSubsequentScreenToScreenColorExpandFill(ScrnInfoPtr pScrn,
67                                                        int x, int y, int w,
68                                                        int h, int srcx,
69                                                        int srcy, int offset);
70#endif
71static void TDFXSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn,
72                                                   int fg, int bg, int rop,
73                                                   unsigned int planemask);
74static void TDFXSubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn,
75                                                     int x, int y,
76                                                     int w, int h,
77                                                     int skipleft);
78static void TDFXSubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno);
79
80void
81TDFXNeedSync(ScrnInfoPtr pScrn) {
82  TDFXPtr pTDFX = TDFXPTR(pScrn);
83  pTDFX->syncDone=FALSE;
84  pTDFX->AccelInfoRec->NeedToSync = TRUE;
85}
86
87void
88TDFXFirstSync(ScrnInfoPtr pScrn) {
89  TDFXPtr pTDFX = TDFXPTR(pScrn);
90
91  if (!pTDFX->syncDone) {
92#ifdef XF86DRI
93    if (pTDFX->directRenderingEnabled) {
94      DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
95      TDFXSwapContextFifo(screenInfo.screens[pScrn->scrnIndex]);
96    }
97#endif
98    pTDFX->syncDone=TRUE;
99    pTDFX->sync(pScrn);
100  }
101}
102
103void
104TDFXCheckSync(ScrnInfoPtr pScrn) {
105  TDFXPtr pTDFX = TDFXPTR(pScrn);
106
107  if (pTDFX->syncDone) {
108    pTDFX->sync(pScrn);
109    pTDFX->syncDone=FALSE;
110#ifdef XF86DRI
111    if (pTDFX->directRenderingEnabled) {
112      DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
113    }
114#endif
115  }
116}
117
118void
119TDFXSelectBuffer(TDFXPtr pTDFX, int which) {
120  int fmt;
121
122  TDFXMakeRoom(pTDFX, 4);
123  DECLARE(SSTCP_SRCBASEADDR|SSTCP_DSTBASEADDR|SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
124  switch (which) {
125  case TDFX_FRONT:
126    if (pTDFX->cpp==1) fmt=pTDFX->stride|(1<<16);
127    else fmt=pTDFX->stride|((pTDFX->cpp+1)<<16);
128    TDFXWriteLong(pTDFX, SST_2D_DSTBASEADDR, pTDFX->fbOffset);
129    TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
130    pTDFX->sst2DDstFmtShadow = fmt;
131    TDFXWriteLong(pTDFX, SST_2D_SRCBASEADDR, pTDFX->fbOffset);
132    TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, fmt);
133    pTDFX->sst2DSrcFmtShadow = fmt;
134    break;
135  case TDFX_BACK:
136    if (pTDFX->cpp==2)
137      fmt=((pTDFX->stride+127)/128)|(3<<16); /* Tiled 16bpp */
138    else
139      fmt=((pTDFX->stride+127)/128)|(5<<16); /* Tiled 32bpp */
140    TDFXWriteLong(pTDFX, SST_2D_DSTBASEADDR, pTDFX->backOffset|BIT(31));
141    TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
142    pTDFX->sst2DDstFmtShadow = fmt;
143    TDFXWriteLong(pTDFX, SST_2D_SRCBASEADDR, pTDFX->backOffset|BIT(31));
144    TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, fmt);
145    pTDFX->sst2DSrcFmtShadow = fmt;
146    break;
147  case TDFX_DEPTH:
148    if (pTDFX->cpp==2)
149      fmt=((pTDFX->stride+127)/128)|(3<<16); /* Tiled 16bpp */
150    else
151      fmt=((pTDFX->stride+127)/128)|(5<<16); /* Tiled 32bpp */
152    TDFXWriteLong(pTDFX, SST_2D_DSTBASEADDR, pTDFX->depthOffset|BIT(31));
153    TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
154    pTDFX->sst2DDstFmtShadow = fmt;
155    TDFXWriteLong(pTDFX, SST_2D_SRCBASEADDR, pTDFX->depthOffset|BIT(31));
156    TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, fmt);
157    pTDFX->sst2DSrcFmtShadow = fmt;
158    break;
159  default:
160    ;
161  }
162}
163
164void
165TDFXSetLFBConfig(TDFXPtr pTDFX) {
166  if (pTDFX->ChipType<=PCI_CHIP_VOODOO3) {
167#if X_BYTE_ORDER == X_BIG_ENDIAN
168    unsigned int lfbmode;
169    lfbmode=TDFXReadLongMMIO(pTDFX, SST_3D_LFBMODE);
170
171    lfbmode&=~BIT(12); /* 0 bit 12 is byte swizzle */
172    lfbmode|=BIT(11); /* 1 bit 11 is word swizzle */
173    lfbmode&=~BIT(10); /* 0 bit 10  ARGB or ABGR */
174    lfbmode&=~BIT(9); /* 0 bit 9 if bit10 = 0:  ARGB else ABGR */
175
176    TDFXWriteLongMMIO(pTDFX, SST_3D_LFBMODE, lfbmode);
177#endif
178    TDFXWriteLongMMIO(pTDFX, LFBMEMORYCONFIG, (pTDFX->backOffset>>12) |
179		      SST_RAW_LFB_ADDR_STRIDE_4K |
180		      ((pTDFX->stride+127)/128)<<SST_RAW_LFB_TILE_STRIDE_SHIFT);
181  } else {
182    int chip;
183    int stride, bits;
184    int TileAperturePitch, lg2TileAperturePitch;
185    if (pTDFX->cpp==2) stride=pTDFX->stride;
186    else stride=4*pTDFX->stride/pTDFX->cpp;
187    bits=pTDFX->backOffset>>12;
188    for (lg2TileAperturePitch = 0, TileAperturePitch = 1024;
189         (lg2TileAperturePitch < 5) &&
190             TileAperturePitch < stride;
191         lg2TileAperturePitch += 1, TileAperturePitch <<= 1);
192#if	0
193    fprintf(stderr, "Using %d (== lg2(%d)-10) for tile aperture pitch\n",
194            lg2TileAperturePitch, TileAperturePitch);
195    fprintf(stderr, "stride == %d\n", stride);
196#endif
197    for (chip=0; chip<pTDFX->numChips; chip++) {
198      TDFXWriteChipLongMMIO(pTDFX, chip, LFBMEMORYCONFIG, (bits&0x1FFF) |
199			    SST_RAW_LFB_ADDR_STRIDE(lg2TileAperturePitch) |
200			    ((bits&0x6000)<<10) |
201			    ((stride+127)/128)<<SST_RAW_LFB_TILE_STRIDE_SHIFT);
202    }
203  }
204}
205
206Bool
207TDFXAccelInit(ScreenPtr pScreen)
208{
209  XAAInfoRecPtr infoPtr;
210  ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
211  TDFXPtr pTDFX = TDFXPTR(pScrn);
212  CARD32 commonFlags;
213
214  pTDFX->AccelInfoRec = infoPtr = XAACreateInfoRec();
215  if (!infoPtr) return FALSE;
216
217  infoPtr->Flags = PIXMAP_CACHE | OFFSCREEN_PIXMAPS | LINEAR_FRAMEBUFFER;
218
219  infoPtr->Sync = pTDFX->sync;
220
221  infoPtr->SetClippingRectangle = TDFXSetClippingRectangle;
222  infoPtr->DisableClipping = TDFXDisableClipping;
223  infoPtr->ClippingFlags = HARDWARE_CLIP_SCREEN_TO_SCREEN_COLOR_EXPAND |
224    HARDWARE_CLIP_SCREEN_TO_SCREEN_COPY |
225    HARDWARE_CLIP_MONO_8x8_FILL |
226    HARDWARE_CLIP_COLOR_8x8_FILL |
227    HARDWARE_CLIP_SOLID_FILL |
228    HARDWARE_CLIP_DASHED_LINE |
229    HARDWARE_CLIP_SOLID_LINE;
230
231  miSetZeroLineBias(pScreen, OCTANT2 | OCTANT5 | OCTANT7 | OCTANT8);
232
233  commonFlags = BIT_ORDER_IN_BYTE_MSBFIRST | NO_PLANEMASK;
234
235  infoPtr->SetupForSolidFill = TDFXSetupForSolidFill;
236  infoPtr->SubsequentSolidFillRect = TDFXSubsequentSolidFillRect;
237  infoPtr->SolidFillFlags = commonFlags;
238
239  infoPtr->SetupForSolidLine = TDFXSetupForSolidLine;
240  infoPtr->SubsequentSolidTwoPointLine = TDFXSubsequentSolidTwoPointLine;
241  infoPtr->SubsequentSolidHorVertLine = TDFXSubsequentSolidHorVertLine;
242  infoPtr->SolidLineFlags = commonFlags;
243
244  infoPtr->SetupForDashedLine = TDFXSetupForDashedLine;
245  infoPtr->SubsequentDashedTwoPointLine = TDFXSubsequentDashedTwoPointLine;
246  infoPtr->DashedLineFlags = commonFlags | LINE_PATTERN_LSBFIRST_LSBJUSTIFIED;
247  infoPtr->DashPatternMaxLength = 32;
248
249  infoPtr->NonTEGlyphRenderer = TDFXNonTEGlyphRenderer;
250  infoPtr->NonTEGlyphRendererFlags = commonFlags;
251
252  infoPtr->SetupForScreenToScreenCopy = TDFXSetupForScreenToScreenCopy;
253  infoPtr->SubsequentScreenToScreenCopy = TDFXSubsequentScreenToScreenCopy;
254  infoPtr->ScreenToScreenCopyFlags = commonFlags;
255
256  /* When we're using the fifo we have to use indirect expansion */
257  pTDFX->scanlineColorExpandBuffers[0] = xalloc((pScrn->virtualX+62)/32*4);
258  pTDFX->scanlineColorExpandBuffers[1] = xalloc((pScrn->virtualX+62)/32*4);
259  infoPtr->NumScanlineColorExpandBuffers=2;
260  infoPtr->ScanlineColorExpandBuffers=pTDFX->scanlineColorExpandBuffers;
261  infoPtr->SetupForScanlineCPUToScreenColorExpandFill =
262    TDFXSetupForCPUToScreenColorExpandFill;
263  infoPtr->SubsequentScanlineCPUToScreenColorExpandFill =
264    TDFXSubsequentCPUToScreenColorExpandFill;
265  infoPtr->SubsequentColorExpandScanline =
266    TDFXSubsequentColorExpandScanline;
267  infoPtr->ScanlineCPUToScreenColorExpandFillFlags = NO_PLANEMASK |
268#if X_BYTE_ORDER == X_LITTLE_ENDIAN
269    BIT_ORDER_IN_BYTE_MSBFIRST |
270#endif
271    CPU_TRANSFER_PAD_DWORD | SCANLINE_PAD_DWORD |
272    LEFT_EDGE_CLIPPING; /* | LEFT_EDGE_CLIPPING_NEGATIVE_X; */
273
274  infoPtr->SetupForMono8x8PatternFill = TDFXSetupForMono8x8PatternFill;
275  infoPtr->SubsequentMono8x8PatternFillRect =
276    TDFXSubsequentMono8x8PatternFillRect;
277  infoPtr->Mono8x8PatternFillFlags = commonFlags |
278    HARDWARE_PATTERN_PROGRAMMED_BITS |
279    HARDWARE_PATTERN_PROGRAMMED_ORIGIN |
280    HARDWARE_PATTERN_SCREEN_ORIGIN;
281
282#ifdef ENABLE_SS_COLOR_EXPAND_FILL
283  /* This causes us to fail compliance */
284  /* I suspect 1bpp pixmaps are getting written to cache incorrectly */
285  infoPtr->SetupForScreenToScreenColorExpandFill =
286    TDFXSetupForScreenToScreenColorExpandFill;
287  infoPtr->SubsequentScreenToScreenColorExpandFill =
288    TDFXSubsequentScreenToScreenColorExpandFill;
289  infoPtr->ScreenToScreenColorExpandFillFlags = commonFlags;
290#endif
291
292  pTDFX->PciCnt=TDFXReadLongMMIO(pTDFX, 0)&0x1F;
293  pTDFX->PrevDrawState=pTDFX->DrawState=0;
294
295  pTDFX->ModeReg.srcbaseaddr=pTDFX->fbOffset;
296  TDFXWriteLongMMIO(pTDFX, SST_2D_SRCBASEADDR, pTDFX->ModeReg.srcbaseaddr);
297  pTDFX->ModeReg.dstbaseaddr=pTDFX->fbOffset;
298  TDFXWriteLongMMIO(pTDFX, SST_2D_DSTBASEADDR, pTDFX->ModeReg.dstbaseaddr);
299
300  pTDFX->sst2DSrcFmtShadow = TDFXReadLongMMIO(pTDFX, SST_2D_SRCFORMAT);
301  pTDFX->sst2DDstFmtShadow = TDFXReadLongMMIO(pTDFX, SST_2D_DSTFORMAT);
302
303  /* Fill in acceleration functions */
304  return XAAInit(pScreen, infoPtr);
305}
306
307static void TDFXMakeRoomNoProp(TDFXPtr pTDFX, int size) {
308  int stat;
309
310  pTDFX->PciCnt-=size;
311  if (pTDFX->PciCnt<1) {
312    do {
313      stat=TDFXReadLongMMIO(pTDFX, 0);
314      pTDFX->PciCnt=stat&0x1F;
315    } while (pTDFX->PciCnt<size);
316  }
317}
318
319static void TDFXSendNOPNoProp(ScrnInfoPtr pScrn)
320{
321  TDFXPtr pTDFX;
322
323  pTDFX=TDFXPTR(pScrn);
324  TDFXMakeRoomNoProp(pTDFX, 1);
325  TDFXWriteLongMMIO(pTDFX, SST_2D_COMMAND, SST_2D_NOP);
326}
327
328void TDFXSync(ScrnInfoPtr pScrn)
329{
330  TDFXPtr pTDFX;
331  int i;
332  int stat;
333
334  TDFXTRACEACCEL("TDFXSync\n");
335  pTDFX=TDFXPTR(pScrn);
336
337  TDFXSendNOPNoProp(pScrn);
338  i=0;
339  do {
340    stat=TDFXReadLongMMIO(pTDFX, 0);
341    if (stat&SST_BUSY) i=0; else i++;
342  } while (i<3);
343  pTDFX->PciCnt=stat&0x1F;
344}
345
346static void
347TDFXMatchState(TDFXPtr pTDFX)
348{
349  if (pTDFX->PrevDrawState==pTDFX->DrawState) return;
350
351  /* Do we need to set a clipping rectangle? */
352  if (pTDFX->DrawState&DRAW_STATE_CLIPPING)
353    pTDFX->Cmd |= SST_2D_USECLIP1;
354  else
355    pTDFX->Cmd &= ~SST_2D_USECLIP1;
356
357  /* Do we need to set transparency? */
358  TDFXMakeRoom(pTDFX, 1);
359  DECLARE(SSTCP_COMMANDEXTRA);
360  if (pTDFX->DrawState&DRAW_STATE_TRANSPARENT) {
361    TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, SST_2D_SRC_COLORKEY_EX);
362  } else {
363    TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, 0);
364  }
365
366  /* Has the previous routine left clip1 changed? Reset it. */
367  if (pTDFX->DrawState&DRAW_STATE_CLIP1CHANGED) {
368    TDFXMakeRoom(pTDFX, 2);
369    DECLARE(SSTCP_CLIP1MIN|SSTCP_CLIP1MAX);
370    TDFXWriteLong(pTDFX, SST_2D_CLIP1MIN, pTDFX->ModeReg.clip1min);
371    TDFXWriteLong(pTDFX, SST_2D_CLIP1MAX, pTDFX->ModeReg.clip1max);
372    pTDFX->DrawState&=~DRAW_STATE_CLIP1CHANGED;
373  }
374
375  pTDFX->PrevDrawState=pTDFX->DrawState;
376}
377
378static void
379TDFXClearState(ScrnInfoPtr pScrn)
380{
381  TDFXPtr pTDFX;
382
383  pTDFX=TDFXPTR(pScrn);
384  pTDFX->Cmd=0;
385  pTDFX->DrawState&=~DRAW_STATE_TRANSPARENT;
386  /* Make sure we've done a sync */
387  TDFXFirstSync(pScrn);
388}
389
390static void
391TDFXSetClippingRectangle(ScrnInfoPtr pScrn, int left, int top, int right,
392			 int bottom)
393{
394  TDFXPtr pTDFX;
395
396  TDFXTRACEACCEL("TDFXSetClippingRectangle %d,%d to %d,%d\n", left, top,
397		 right, bottom);
398  pTDFX=TDFXPTR(pScrn);
399
400  pTDFX->ModeReg.clip1min=(top&0xFFF)<<16 | (left&0xFFF);
401  pTDFX->ModeReg.clip1max=((bottom+1)&0xFFF)<<16 | ((right+1)&0xFFF);
402
403  pTDFX->DrawState|=DRAW_STATE_CLIPPING|DRAW_STATE_CLIP1CHANGED;
404}
405
406static void
407TDFXDisableClipping(ScrnInfoPtr pScrn)
408{
409  TDFXPtr pTDFX;
410
411  TDFXTRACEACCEL("TDFXDisableClippingRectangle\n");
412  pTDFX=TDFXPTR(pScrn);
413
414  pTDFX->DrawState&=~DRAW_STATE_CLIPPING;
415}
416
417void
418TDFXSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop,
419			       unsigned int planemask, int trans_color)
420{
421  TDFXPtr pTDFX;
422  int fmt;
423
424  TDFXTRACEACCEL("TDFXSetupForScreenToScreenCopy\n xdir=%d ydir=%d "
425		 "rop=%d planemask=%d trans_color=%d\n",
426		 xdir, ydir, rop, planemask, trans_color);
427  pTDFX=TDFXPTR(pScrn);
428  TDFXClearState(pScrn);
429
430  if (trans_color!=-1) {
431    TDFXMakeRoom(pTDFX, 3);
432    DECLARE(SSTCP_SRCCOLORKEYMIN|SSTCP_SRCCOLORKEYMAX|SSTCP_ROP);
433    TDFXWriteLong(pTDFX, SST_2D_SRCCOLORKEYMIN, trans_color);
434    TDFXWriteLong(pTDFX, SST_2D_SRCCOLORKEYMAX, trans_color);
435    TDFXWriteLong(pTDFX, SST_2D_ROP, TDFXROPCvt[GXnoop]<<8);
436    pTDFX->DrawState|=DRAW_STATE_TRANSPARENT;
437  }
438  pTDFX->Cmd = (TDFXROPCvt[rop]<<24) | SST_2D_SCRNTOSCRNBLIT;
439  if (xdir==-1) pTDFX->Cmd |= SST_2D_X_RIGHT_TO_LEFT;
440  if (ydir==-1) pTDFX->Cmd |= SST_2D_Y_BOTTOM_TO_TOP;
441  if (pTDFX->cpp==1) fmt=pTDFX->stride|(1<<16);
442  else fmt=pTDFX->stride|((pTDFX->cpp+1)<<16);
443
444  TDFXMakeRoom(pTDFX, 2);
445  DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
446  TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
447  pTDFX->sst2DDstFmtShadow = fmt;
448  TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, fmt);
449  pTDFX->sst2DSrcFmtShadow = fmt;
450}
451
452void
453TDFXSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int srcX, int srcY,
454				 int dstX, int dstY, int w, int h)
455{
456  TDFXPtr pTDFX;
457
458  TDFXTRACEACCEL("TDFXSubsequentScreenToScreenCopy\n srcX=%d srcY=%d"
459                 " dstX=%d dstY=%d w=%d h=%d\n", srcX, srcY, dstX, dstY, w, h);
460  pTDFX=TDFXPTR(pScrn);
461  TDFXMatchState(pTDFX);
462
463  if (pTDFX->Cmd&SST_2D_Y_BOTTOM_TO_TOP) {
464    srcY += h-1;
465    dstY += h-1;
466  }
467  if (pTDFX->Cmd&SST_2D_X_RIGHT_TO_LEFT) {
468    srcX += w-1;
469    dstX += w-1;
470  }
471  if ((srcY>=dstY-32 && srcY<=dstY)||
472      (srcY>=pTDFX->prevBlitDest.y1-32 && srcY<=pTDFX->prevBlitDest.y1)) {
473    TDFXSendNOP(pScrn);
474  }
475  pTDFX->sync(pScrn);
476
477  TDFXMakeRoom(pTDFX, 4);
478  DECLARE(SSTCP_DSTSIZE|SSTCP_DSTXY|SSTCP_SRCXY|SSTCP_COMMAND);
479  TDFXWriteLong(pTDFX, SST_2D_SRCXY, (srcX&0x1FFF) | ((srcY&0x1FFF)<<16));
480  TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, (w&0x1FFF) | ((h&0x1FFF)<<16));
481  TDFXWriteLong(pTDFX, SST_2D_DSTXY, (dstX&0x1FFF) | ((dstY&0x1FFF)<<16));
482  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd|SST_2D_GO);
483
484  pTDFX->prevBlitDest.y1=dstY;
485}
486
487void
488TDFXSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop,
489		      unsigned int planemask)
490{
491  TDFXPtr pTDFX;
492  int fmt;
493
494  TDFXTRACEACCEL("TDFXSetupForSolidFill color=%d rop=%d planemask=%d\n",
495                 color, rop, planemask);
496  pTDFX=TDFXPTR(pScrn);
497  TDFXClearState(pScrn);
498
499  pTDFX->Cmd=TDFXROPCvt[rop]<<24;
500  if (pTDFX->cpp==1) fmt=(1<<16)|pTDFX->stride;
501  else fmt=((pTDFX->cpp+1)<<16)|pTDFX->stride;
502
503  TDFXMakeRoom(pTDFX, 3);
504  DECLARE(SSTCP_DSTFORMAT|SSTCP_COLORFORE|
505		 SSTCP_COLORBACK);
506  TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
507  pTDFX->sst2DDstFmtShadow = fmt;
508  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, color);
509  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, color);
510}
511
512void
513TDFXSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h)
514{
515  /* Also called by TDFXSubsequentMono8x8PatternFillRect */
516  TDFXPtr pTDFX;
517
518  TDFXTRACEACCEL("TDFXSubsequentSolidFillRect x=%d y=%d w=%d h=%d\n",
519		 x, y, w, h);
520  pTDFX=TDFXPTR(pScrn);
521  TDFXMatchState(pTDFX);
522
523  TDFXMakeRoom(pTDFX, 3);
524  DECLARE(SSTCP_DSTSIZE|SSTCP_DSTXY|SSTCP_COMMAND);
525  TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, ((h&0x1FFF)<<16) | (w&0x1FFF));
526  TDFXWriteLong(pTDFX, SST_2D_DSTXY, ((y&0x1FFF)<<16) | (x&0x1FFF));
527  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd | SST_2D_RECTANGLEFILL |
528		SST_2D_GO);
529}
530
531static void
532TDFXSetupForMono8x8PatternFill(ScrnInfoPtr pScrn, int patx, int paty,
533			       int fg, int bg, int rop, unsigned int planemask)
534{
535  TDFXPtr pTDFX;
536  int fmt;
537
538  TDFXTRACEACCEL("TDFXSetupForMono8x8PatternFill patx=%x paty=%x fg=%d"
539                 " bg=%d rop=%d planemask=%d\n", patx, paty, fg, bg, rop,
540		 planemask);
541  pTDFX=TDFXPTR(pScrn);
542  TDFXClearState(pScrn);
543
544  pTDFX->Cmd = (TDFXROPCvt[rop+ROP_PATTERN_OFFSET]<<24) |
545    SST_2D_MONOCHROME_PATTERN;
546  if (bg==-1) {
547    pTDFX->Cmd |= SST_2D_TRANSPARENT_MONOCHROME;
548  }
549  if (pTDFX->cpp==1) fmt=(1<<16)|pTDFX->stride;
550  else fmt=((pTDFX->cpp+1)<<16)|pTDFX->stride;
551
552  TDFXMakeRoom(pTDFX, 5);
553  DECLARE(SSTCP_DSTFORMAT|SSTCP_PATTERN0ALIAS
554		  |SSTCP_PATTERN1ALIAS|SSTCP_COLORFORE|
555		  SSTCP_COLORBACK);
556  TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
557  pTDFX->sst2DDstFmtShadow = fmt;
558  TDFXWriteLong(pTDFX, SST_2D_PATTERN0, patx);
559  TDFXWriteLong(pTDFX, SST_2D_PATTERN1, paty);
560  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, bg);
561  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, fg);
562}
563
564static void
565TDFXSubsequentMono8x8PatternFillRect(ScrnInfoPtr pScrn, int patx, int paty,
566				     int x, int y, int w, int h)
567{
568  TDFXPtr pTDFX;
569
570  TDFXTRACEACCEL("TDFXSubsequentMono8x8PatternFillRect patx=%x paty=%x"
571                 " x=%d y=%d w=%d h=%d\n", patx, paty, x, y, w, h);
572  pTDFX=TDFXPTR(pScrn);
573
574  pTDFX->Cmd |= ((patx&0x7)<<SST_2D_X_PATOFFSET_SHIFT) |
575    ((paty&0x7)<<SST_2D_Y_PATOFFSET_SHIFT);
576
577  TDFXSubsequentSolidFillRect(pScrn, x, y, w, h);
578}
579
580static void
581TDFXSetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
582		      unsigned int planemask)
583{
584  TDFXPtr pTDFX;
585
586  TDFXTRACEACCEL("TDFXSetupForSolidLine\n");
587  pTDFX=TDFXPTR(pScrn);
588  TDFXClearState(pScrn);
589
590  pTDFX->Cmd = (TDFXROPCvt[rop]<<24);
591
592  TDFXMakeRoom(pTDFX, 2);
593  DECLARE(SSTCP_COLORFORE|SSTCP_COLORBACK);
594  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, color);
595  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, color);
596}
597
598static void
599TDFXSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn, int srcx, int srcy,
600				int dstx, int dsty, int flags)
601{
602  /* Also used by TDFXSubsequentDashedTwoPointLine */
603  TDFXPtr pTDFX;
604
605  TDFXTRACEACCEL("TDFXSubsequentSolidTwoPointLine "
606		 "srcx=%d srcy=%d dstx=%d dsty=%d flags=%d\n",
607		 srcx, srcy, dstx, dsty, flags);
608  pTDFX=TDFXPTR(pScrn);
609  TDFXMatchState(pTDFX);
610
611  if (flags&OMIT_LAST) pTDFX->Cmd|=SST_2D_POLYLINE;
612  else pTDFX->Cmd|=SST_2D_LINE;
613
614  TDFXMakeRoom(pTDFX, 3);
615  DECLARE(SSTCP_SRCXY|SSTCP_DSTXY|SSTCP_COMMAND);
616  TDFXWriteLong(pTDFX, SST_2D_SRCXY, (srcy&0x1FFF)<<16 | (srcx&0x1FFF));
617  TDFXWriteLong(pTDFX, SST_2D_DSTXY, (dsty&0x1FFF)<<16 | (dstx&0x1FFF));
618  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd|SST_2D_GO);
619}
620
621static void
622TDFXSubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len,
623			       int dir)
624{
625  TDFXPtr pTDFX;
626
627  TDFXTRACEACCEL("TDFXSubsequentSolidHorVertLine\n");
628  pTDFX=TDFXPTR(pScrn);
629  TDFXMatchState(pTDFX);
630
631  TDFXMakeRoom(pTDFX, 3);
632  DECLARE(SSTCP_SRCXY|SSTCP_DSTXY|SSTCP_COMMAND);
633  TDFXWriteLong(pTDFX, SST_2D_SRCXY, (y&0x1FFF)<<16 | (x&0x1FFF));
634  if (dir == DEGREES_0)
635    TDFXWriteLong(pTDFX, SST_2D_DSTXY, (y&0x1FFF)<<16 | ((x+len)&0x1FFF));
636  else
637    TDFXWriteLong(pTDFX, SST_2D_DSTXY, ((y+len)&0x1FFF)<<16 | (x&0x1FFF));
638  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd|SST_2D_POLYLINE|SST_2D_GO);
639}
640
641static void
642TDFXNonTEGlyphRenderer(ScrnInfoPtr pScrn, int x, int y, int n,
643		       NonTEGlyphPtr glyphs, BoxPtr pbox, int fg, int rop,
644		       unsigned int planemask)
645{
646  TDFXPtr pTDFX;
647  int ndwords;
648  int g;
649  NonTEGlyphPtr glyph;
650
651  TDFXTRACEACCEL("TDFXNonTEGlyphRenderer\n");
652  pTDFX=TDFXPTR(pScrn);
653  TDFXClearState(pScrn);
654  /* Don't bother fixing clip1, we're going to change it anyway */
655  pTDFX->DrawState&=~DRAW_STATE_CLIP1CHANGED;
656  TDFXMatchState(pTDFX);
657  /* We're changing clip1 so make sure we use it and flag it */
658  pTDFX->Cmd|=SST_2D_USECLIP1;
659  pTDFX->DrawState|=DRAW_STATE_CLIP1CHANGED;
660
661  pTDFX->Cmd|=(TDFXROPCvt[rop]<<24)|SST_2D_TRANSPARENT_MONOCHROME;
662  pTDFX->Cmd|=SST_2D_HOSTTOSCRNBLIT;
663
664  TDFXMakeRoom(pTDFX, 6);
665  DECLARE(SSTCP_CLIP1MIN|SSTCP_CLIP1MAX|SSTCP_SRCFORMAT|
666	  SSTCP_SRCXY|SSTCP_COLORFORE|SSTCP_COMMAND);
667  TDFXWriteLong(pTDFX, SST_2D_CLIP1MIN, ((pbox->y1&0x1FFF)<<16) |
668		(pbox->x1&0x1FFF));
669  TDFXWriteLong(pTDFX, SST_2D_CLIP1MAX, ((pbox->y2&0x1FFF)<<16) |
670		(pbox->x2&0x1FFF));
671#if X_BYTE_ORDER == X_BIG_ENDIAN
672  TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, SST_2D_PIXFMT_1BPP |
673		SST_2D_SOURCE_PACKING_DWORD | BIT(20));
674#else
675  TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, SST_2D_PIXFMT_1BPP |
676		SST_2D_SOURCE_PACKING_DWORD);
677#endif
678  pTDFX->sst2DSrcFmtShadow = SST_2D_PIXFMT_1BPP | SST_2D_SOURCE_PACKING_DWORD;
679  TDFXWriteLong(pTDFX, SST_2D_SRCXY, 0);
680  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, fg);
681  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd);
682
683  for (g=0, glyph=glyphs; g<n; g++, glyph++) {
684    int dx = x+glyph->start;
685    int dy = y-glyph->yoff;
686    int w = glyph->end - glyph->start;
687    int *glyph_data = (int*)glyph->bits;
688
689    if (!glyph->srcwidth) continue;
690    ndwords = (glyph->srcwidth+3)>>2;
691    ndwords *= glyph->height;
692
693    TDFXMakeRoom(pTDFX, 2);
694    DECLARE(SSTCP_DSTSIZE|SSTCP_DSTXY);
695    TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, ((glyph->height&0x1FFF)<<16) |
696		  (w&0x1FFF));
697    TDFXWriteLong(pTDFX, SST_2D_DSTXY, ((dy&0x1FFF)<<16) | (dx&0x1FFF));
698
699    do {
700      int i = ndwords;
701      int j;
702
703      if (i>30) i=30;
704      TDFXMakeRoom(pTDFX, i);
705      DECLARE_LAUNCH(i, 0);
706      for (j=0; j<i; j++) {
707#if X_BYTE_ORDER == X_BIG_ENDIAN
708	TDFXWriteLong(pTDFX, SST_2D_LAUNCH, *glyph_data);
709#else
710	TDFXWriteLong(pTDFX, SST_2D_LAUNCH, XAAReverseBitOrder(*glyph_data));
711#endif
712	glyph_data++;
713      }
714      ndwords -= i;
715    } while (ndwords);
716  }
717}
718
719static void
720TDFXSetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop,
721                       unsigned int planemask, int length,
722		       unsigned char *pattern)
723{
724  TDFXPtr pTDFX;
725#if X_BYTE_ORDER == X_BIG_ENDIAN
726  unsigned int pat = *(unsigned int *)pattern;
727#endif
728
729  TDFXTRACEACCEL("TDFXSetupForDashedLine\n");
730  pTDFX=TDFXPTR(pScrn);
731
732#if X_BYTE_ORDER == X_BIG_ENDIAN
733  pat=((pat & 0xAAAAAAAA) >> 1) | ((pat & 0x55555555) << 1);
734  pat=((pat & 0xCCCCCCCC) >> 2) | ((pat & 0x33333333) << 2);
735  pat=((pat & 0xF0F0F0F0) >> 4) | ((pat & 0x0F0F0F0F) << 4);
736  pat=((pat & 0xFF00FF00) >> 8) | ((pat & 0x00FF00FF) << 8);
737  pat=((pat & 0xFFFF0000) >> 16) | ((pat & 0x0000FFFF) << 16);
738#endif
739
740  TDFXClearState(pScrn);
741
742  pTDFX->Cmd = (TDFXROPCvt[rop]<<24) | SST_2D_STIPPLE_LINE;
743  if(bg == -1) {
744    pTDFX->Cmd |= SST_2D_TRANSPARENT_MONOCHROME;
745  }
746  pTDFX->DashedLineSize = ((length-1)&0xFF)+1;
747
748  TDFXMakeRoom(pTDFX, 3);
749  DECLARE(SSTCP_COLORFORE|SSTCP_COLORBACK|SSTCP_LINESTIPPLE);
750#if X_BYTE_ORDER == X_BIG_ENDIAN
751  TDFXWriteLong(pTDFX, SST_2D_LINESTIPPLE, pat);
752#else
753  TDFXWriteLong(pTDFX, SST_2D_LINESTIPPLE, *(int *)pattern);
754#endif
755  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, bg);
756  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, fg);
757}
758
759static void
760TDFXSubsequentDashedTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1,
761                                 int x2, int y2, int flags, int phase)
762{
763  TDFXPtr pTDFX;
764  int linestyle;
765
766  TDFXTRACEACCEL("TDFXSubsequentDashedTwoPointLine\n");
767  pTDFX=TDFXPTR(pScrn);
768
769  linestyle = ((pTDFX->DashedLineSize-1)<<8) |
770              (((phase%pTDFX->DashedLineSize)&0x1F)<<24);
771
772  TDFXMakeRoom(pTDFX, 1);
773  DECLARE(SSTCP_LINESTYLE);
774  TDFXWriteLong(pTDFX, SST_2D_LINESTYLE, linestyle);
775
776  TDFXSubsequentSolidTwoPointLine(pScrn, x1, y1, x2, y2, flags);
777}
778
779#ifdef ENABLE_SS_COLOR_EXPAND_FILL
780static void
781TDFXSetupForScreenToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, int bg,
782                                          int rop, unsigned int planemask)
783{
784  TDFXPtr pTDFX;
785
786  TDFXTRACEACCEL("TDFXSetupForScreenToScreenColorExpandFill\n");
787  pTDFX=TDFXPTR(pScrn);
788  TDFXClearState(pScrn);
789
790  TDFXMatchState(pTDFX);
791  pTDFX->Cmd|=SST_2D_SCRNTOSCRNBLIT|(TDFXROPCvt[rop]<<24);
792
793  if (bg==-1) {
794    pTDFX->Cmd |= SST_2D_TRANSPARENT_MONOCHROME;
795  }
796  TDFXMakeRoom(pTDFX, 2);
797  DECLARE(SSTCP_COLORFORE|SSTCP_COLORBACK);
798  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, bg);
799  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, fg);
800}
801
802static void
803TDFXSubsequentScreenToScreenColorExpandFill(ScrnInfoPtr pScrn, int x, int y,
804                                            int w, int h, int srcx, int srcy,
805                                            int offset)
806{
807  TDFXPtr pTDFX;
808  int fmt;
809
810  TDFXTRACEACCEL("TDFXSubsequentScreenToScreenColorExpandFill "
811		 "x=%d y=%d w=%d h=%d srcx=%d srcy=%d offset=%d\n",
812		 x, y, w, h, srcx, srcy, offset);
813  pTDFX=TDFXPTR(pScrn);
814  /* Don't bother resetting clip1 since we're changing it anyway */
815  pTDFX->DrawState&=~DRAW_STATE_CLIP1CHANGED;
816  TDFXMatchState(pTDFX);
817  /* We're changing clip1 so make sure we use it and flag it */
818  pTDFX->Cmd|=SST_2D_USECLIP1;
819  pTDFX->DrawState|=DRAW_STATE_CLIP1CHANGED;
820
821  if (srcy>=pTDFX->prevBlitDest.y1-8 && srcy<=pTDFX->prevBlitDest.y1) {
822    TDFXSendNOP(pScrn);
823  }
824
825  if (pTDFX->cpp==1) fmt=(1<<16)|pTDFX->stride;
826  else fmt=(pTDFX->cpp+1)<<16|pTDFX->stride;
827
828  TDFXMakeRoom(pTDFX, 8);
829  DECLARE(SSTCP_SRCFORMAT|SSTCP_SRCXY|SSTCP_DSTFORMAT |
830	  SSTCP_DSTSIZE|SSTCP_DSTXY|SSTCP_COMMAND |
831	  SSTCP_CLIP1MIN|SSTCP_CLIP1MAX);
832  TDFXWriteLong(pTDFX,SST_2D_DSTFORMAT, fmt);
833  pTDFX->sst2DDstFmtShadow = fmt;
834  TDFXWriteLong(pTDFX,SST_2D_CLIP1MIN, (x&0x1FFF) | ((y&0x1FFF)<<16));
835  TDFXWriteLong(pTDFX,SST_2D_CLIP1MAX, ((x+w)&0x1FFF) | (((y+h)&0x1FFF)<<16));
836  TDFXWriteLong(pTDFX,SST_2D_SRCFORMAT, pTDFX->stride);
837  pTDFX->sst2DSrcFmtShadow = pTDFX->stride;
838  TDFXWriteLong(pTDFX,SST_2D_SRCXY, (srcx&0x1FFF) | ((srcy&0x1FFF)<<16));
839  TDFXWriteLong(pTDFX,SST_2D_DSTSIZE, ((w+offset)&0x1FFF) | ((h&0x1FFF)<<16));
840  TDFXWriteLong(pTDFX,SST_2D_DSTXY, ((x-offset)&0x1FFF) | ((y&0x1FFF)<<16));
841  TDFXWriteLong(pTDFX,SST_2D_COMMAND, pTDFX->Cmd|SST_2D_GO);
842
843  pTDFX->prevBlitDest.y1=y;
844}
845#endif
846
847static void
848TDFXSetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, int bg,
849                                       int rop, unsigned int planemask)
850{
851  TDFXPtr pTDFX;
852
853  TDFXTRACEACCEL("SetupForCPUToScreenColorExpandFill bg=%x fg=%x rop=%d\n",
854                 bg, fg, rop);
855  pTDFX=TDFXPTR(pScrn);
856  TDFXClearState(pScrn);
857
858  pTDFX->Cmd|=SST_2D_HOSTTOSCRNBLIT|(TDFXROPCvt[rop]<<24);
859
860  if (bg == -1) {
861    pTDFX->Cmd |= SST_2D_TRANSPARENT_MONOCHROME;
862  }
863
864  TDFXMakeRoom(pTDFX, 2);
865  DECLARE(SSTCP_COLORBACK|SSTCP_COLORFORE);
866  TDFXWriteLong(pTDFX, SST_2D_COLORBACK, bg);
867  TDFXWriteLong(pTDFX, SST_2D_COLORFORE, fg);
868}
869
870static void
871TDFXSubsequentCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int x, int y,
872                                         int w, int h, int skipleft)
873{
874  TDFXPtr pTDFX;
875  int fmt;
876
877  TDFXTRACEACCEL("SubsequentCPUToScreenColorExpandFill x=%d y=%d w=%d h=%d"
878                 " skipleft=%d\n", x, y, w, h, skipleft);
879  pTDFX = TDFXPTR(pScrn);
880
881  /* We're changing clip1 anyway, so don't bother to reset it */
882  pTDFX->DrawState&=~DRAW_STATE_CLIP1CHANGED;
883  TDFXMatchState(pTDFX);
884  /* Make sure we use clip1 and flag it */
885  pTDFX->Cmd|=SST_2D_USECLIP1;
886  pTDFX->DrawState|=DRAW_STATE_CLIP1CHANGED;
887
888  if (pTDFX->cpp==1) fmt=(1<<16)|pTDFX->stride;
889  else fmt=((pTDFX->cpp+1)<<16)|pTDFX->stride;
890  pTDFX->scanlineWidth=w;
891
892  TDFXMakeRoom(pTDFX, 8);
893  DECLARE(SSTCP_CLIP1MIN|SSTCP_CLIP1MAX|SSTCP_SRCFORMAT|
894	  SSTCP_DSTFORMAT|SSTCP_DSTSIZE|SSTCP_SRCXY|
895	  SSTCP_DSTXY|SSTCP_COMMAND);
896  TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, fmt);
897  pTDFX->sst2DDstFmtShadow = fmt;
898  TDFXWriteLong(pTDFX, SST_2D_CLIP1MIN, ((y&0x1FFF)<<16)|(x&0x1FFF));
899  TDFXWriteLong(pTDFX, SST_2D_CLIP1MAX, (((y+h)&0x1FFF)<<16)|((x+w)&0x1FFF));
900#if X_BYTE_ORDER == X_BIG_ENDIAN
901  /* bit 20 byte swizzle */
902  TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, ((((w+31)/32)*4) & 0x3FFF) | BIT(20));
903#else
904  TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT,  (((w+31)/32)*4) & 0x3FFF);
905#endif
906  pTDFX->sst2DSrcFmtShadow = (((w+31)/32)*4) & 0x3FFF;
907  TDFXWriteLong(pTDFX, SST_2D_SRCXY, skipleft&0x1F);
908  TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, ((w-skipleft)&0x1FFF)|((h&0x1FFF)<<16));
909  TDFXWriteLong(pTDFX, SST_2D_DSTXY, ((x+skipleft)&0x1FFF) | ((y&0x1FFF)<<16));
910  TDFXWriteLong(pTDFX, SST_2D_COMMAND, pTDFX->Cmd|SST_2D_GO);
911}
912
913static void TDFXSubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno)
914{
915  TDFXPtr pTDFX;
916  int i, size, cnt;
917  CARD32 *pos;
918
919  TDFXTRACEACCEL("SubsequentColorExpandScanline bufno=%d\n", bufno);
920  pTDFX = TDFXPTR(pScrn);
921
922  cnt=(pTDFX->scanlineWidth+31)/32;
923  pos=(CARD32 *)pTDFX->scanlineColorExpandBuffers[bufno];
924  while (cnt>0) {
925    if (cnt>64) size=64;
926    else size=cnt;
927    TDFXMakeRoom(pTDFX, size);
928    DECLARE_LAUNCH(size, 0);
929    for (i=0; i<size; i++, pos++) {
930      TDFXWriteLong(pTDFX, SST_2D_LAUNCH, *pos);
931    }
932    cnt-=size;
933  }
934}
935
936