Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1728 lines
57 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fastfill.c
  3. *
  4. * Fast routine for drawing polygons that aren't complex in shape.
  5. *
  6. * Copyright (c) 1993-1995 Microsoft Corporation
  7. \**************************************************************************/
  8. #include "precomp.h"
  9. #define RIGHT 0
  10. #define LEFT 1
  11. typedef struct _TRAPEZOIDDATA TRAPEZOIDDATA; // Handy forward declaration
  12. typedef VOID (FNTRAPEZOID)(TRAPEZOIDDATA*, LONG, LONG);
  13. // Prototype for trapezoid
  14. // drawing routines
  15. typedef struct _EDGEDATA {
  16. LONG x; // Current x position
  17. LONG dx; // # pixels to advance x on each scan
  18. LONG lError; // Current DDA error
  19. LONG lErrorUp; // DDA error increment on each scan
  20. LONG dN; // Signed delta-y in fixed point form (also known
  21. // as the DDA error adjustment, and used to be
  22. // called 'lErrorDown')
  23. LONG dM; // Signed delta-x in fixed point form
  24. POINTFIX* pptfx; // Points to start of current edge
  25. LONG dptfx; // Delta (in bytes) from pptfx to next point
  26. LONG cy; // Number of scans to go for this edge
  27. LONG bNew; // Set to TRUE when a new DDA must be started
  28. // for the edge.
  29. } EDGEDATA; /* ed, ped */
  30. typedef struct _TRAPEZOIDDATA {
  31. FNTRAPEZOID* pfnTrap; // Pointer to appropriate trapezoid drawing routine,
  32. // or trapezoid clip routine
  33. FNTRAPEZOID* pfnTrapClip;// Pointer to appropriate trapezoid drawing routine
  34. // if doing clipping
  35. PDEV* ppdev; // Pointer to PDEV
  36. EDGEDATA aed[2]; // DDA information for both edges
  37. POINTL ptlBrush; // Brush alignment
  38. LONG yClipTop; // Top of clip rectangle
  39. LONG yClipBottom;// Bottom of clip rectangle
  40. // ATI specific fields follow:
  41. RBRUSH* prb; // Pointer to realized brush
  42. BOOL bOverpaint; // For colour pattern copies, indicates whether
  43. // PATCOPY or not
  44. } TRAPEZOIDDATA; /* td, ptd */
  45. /******************************Public*Routine******************************\
  46. * VOID vClipTrapezoid
  47. *
  48. * Clips a trapezoid.
  49. *
  50. * NOTE: This routine assumes that the polygon's dimensions are small
  51. * enough that its QUOTIENT_REMAINDER calculations won't overflow.
  52. * This means that large polygons must never make it here.
  53. *
  54. \**************************************************************************/
  55. VOID vClipTrapezoid(
  56. TRAPEZOIDDATA* ptd,
  57. LONG yTrapTop,
  58. LONG cyTrapezoid)
  59. {
  60. LONG yTrapBottom;
  61. LONG dN;
  62. LONG lNum;
  63. LONG xDelta;
  64. LONG lError;
  65. yTrapBottom = yTrapTop + cyTrapezoid;
  66. if (yTrapTop < ptd->yClipTop)
  67. {
  68. if ((ptd->aed[LEFT].bNew) &&
  69. (yTrapBottom + ptd->aed[LEFT].cy > ptd->yClipTop))
  70. {
  71. dN = ptd->aed[LEFT].dN;
  72. lNum = ptd->aed[LEFT].dM * (ptd->yClipTop - yTrapTop)
  73. + (ptd->aed[LEFT].lError + dN);
  74. if (lNum >= 0)
  75. {
  76. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  77. }
  78. else
  79. {
  80. lNum = -lNum;
  81. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  82. xDelta = -xDelta;
  83. if (lError != 0)
  84. {
  85. xDelta--;
  86. lError = dN - lError;
  87. }
  88. }
  89. ptd->aed[LEFT].x += xDelta;
  90. ptd->aed[LEFT].lError = lError - dN;
  91. }
  92. if ((ptd->aed[RIGHT].bNew) &&
  93. (yTrapBottom + ptd->aed[RIGHT].cy > ptd->yClipTop))
  94. {
  95. dN = ptd->aed[RIGHT].dN;
  96. lNum = ptd->aed[RIGHT].dM * (ptd->yClipTop - yTrapTop)
  97. + (ptd->aed[RIGHT].lError + dN);
  98. if (lNum >= 0)
  99. {
  100. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  101. }
  102. else
  103. {
  104. lNum = -lNum;
  105. QUOTIENT_REMAINDER(lNum, dN, xDelta, lError);
  106. xDelta = -xDelta;
  107. if (lError != 0)
  108. {
  109. xDelta--;
  110. lError = dN - lError;
  111. }
  112. }
  113. ptd->aed[RIGHT].x += xDelta;
  114. ptd->aed[RIGHT].lError = lError - dN;
  115. }
  116. }
  117. // If this trapezoid vertically intersects our clip rectangle, draw it:
  118. if ((yTrapBottom > ptd->yClipTop) &&
  119. (yTrapTop < ptd->yClipBottom))
  120. {
  121. if (yTrapTop <= ptd->yClipTop)
  122. {
  123. yTrapTop = ptd->yClipTop;
  124. // Have to let trapezoid drawer know that it has to load
  125. // its DDAs for very first trapezoid drawn:
  126. ptd->aed[RIGHT].bNew = TRUE;
  127. ptd->aed[LEFT].bNew = TRUE;
  128. }
  129. if (yTrapBottom >= ptd->yClipBottom)
  130. {
  131. yTrapBottom = ptd->yClipBottom;
  132. }
  133. ptd->pfnTrapClip(ptd, yTrapTop, yTrapBottom - yTrapTop);
  134. }
  135. }
  136. /******************************Public*Routine******************************\
  137. * VOID vI32SolidTrapezoid
  138. *
  139. * Draws a solid trapezoid using a software DDA.
  140. *
  141. \**************************************************************************/
  142. VOID vI32SolidTrapezoid(
  143. TRAPEZOIDDATA* ptd,
  144. LONG yTrapezoid,
  145. LONG cyTrapezoid)
  146. {
  147. PDEV* ppdev;
  148. BYTE* pjIoBase;
  149. LONG xOffset;
  150. LONG lLeftError;
  151. LONG xLeft;
  152. LONG lRightError;
  153. LONG xRight;
  154. LONG lTmp;
  155. EDGEDATA edTmp;
  156. // Note that CUR_Y is already set...
  157. ppdev = ptd->ppdev;
  158. pjIoBase = ppdev->pjIoBase;
  159. xOffset = ppdev->xOffset;
  160. yTrapezoid += ppdev->yOffset;
  161. // If the left and right edges are vertical, simply output as
  162. // a rectangle:
  163. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  164. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  165. {
  166. /////////////////////////////////////////////////////////////////
  167. // Vertical-edge special case
  168. xLeft = ptd->aed[LEFT].x + xOffset;
  169. xRight = ptd->aed[RIGHT].x + xOffset;
  170. if (xLeft > xRight)
  171. {
  172. SWAP(xLeft, xRight, lTmp);
  173. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  174. }
  175. if (xLeft < xRight)
  176. {
  177. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 4);
  178. I32_OW(pjIoBase, CUR_X, xLeft);
  179. I32_OW(pjIoBase, DEST_X_START, xLeft);
  180. I32_OW(pjIoBase, DEST_X_END, xRight);
  181. I32_OW(pjIoBase, DEST_Y_END, yTrapezoid + cyTrapezoid);
  182. }
  183. else
  184. {
  185. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 1);
  186. I32_OW(pjIoBase, CUR_Y, yTrapezoid + cyTrapezoid);
  187. }
  188. }
  189. else
  190. {
  191. lLeftError = ptd->aed[LEFT].lError;
  192. xLeft = ptd->aed[LEFT].x + xOffset;
  193. lRightError = ptd->aed[RIGHT].lError;
  194. xRight = ptd->aed[RIGHT].x + xOffset;
  195. while (TRUE)
  196. {
  197. /////////////////////////////////////////////////////////////////
  198. // Run the DDAs
  199. if (xLeft < xRight)
  200. {
  201. // Note that we don't need to set DEST_X_START because
  202. // we're always doing blts that are only one scan high.
  203. //
  204. // The ATI is nice enough to always automatically advance
  205. // CUR_Y to become DEST_Y_END after the blt is done, so we
  206. // never have to update it:
  207. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 3);
  208. I32_OW(pjIoBase, CUR_X, xLeft);
  209. I32_OW(pjIoBase, DEST_X_END, xRight);
  210. yTrapezoid++;
  211. I32_OW(pjIoBase, DEST_Y_END, yTrapezoid);
  212. }
  213. else if (xLeft > xRight)
  214. {
  215. // We don't bother optimizing this case because we should
  216. // rarely get self-intersecting polygons (if we're slow,
  217. // the app gets what it deserves).
  218. SWAP(xLeft, xRight, lTmp);
  219. SWAP(lLeftError, lRightError, lTmp);
  220. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  221. continue;
  222. }
  223. else
  224. {
  225. yTrapezoid++;
  226. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 1);
  227. I32_OW(pjIoBase, CUR_Y, yTrapezoid);
  228. }
  229. // Advance the right wall:
  230. xRight += ptd->aed[RIGHT].dx;
  231. lRightError += ptd->aed[RIGHT].lErrorUp;
  232. if (lRightError >= 0)
  233. {
  234. lRightError -= ptd->aed[RIGHT].dN;
  235. xRight++;
  236. }
  237. // Advance the left wall:
  238. xLeft += ptd->aed[LEFT].dx;
  239. lLeftError += ptd->aed[LEFT].lErrorUp;
  240. if (lLeftError >= 0)
  241. {
  242. lLeftError -= ptd->aed[LEFT].dN;
  243. xLeft++;
  244. }
  245. cyTrapezoid--;
  246. if (cyTrapezoid == 0)
  247. break;
  248. }
  249. ptd->aed[LEFT].lError = lLeftError;
  250. ptd->aed[LEFT].x = xLeft - xOffset;
  251. ptd->aed[RIGHT].lError = lRightError;
  252. ptd->aed[RIGHT].x = xRight - xOffset;
  253. }
  254. }
  255. /******************************Public*Routine******************************\
  256. * VOID vI32ColorPatternTrapezoid
  257. *
  258. * Draws a patterned trapezoid using a software DDA.
  259. *
  260. \**************************************************************************/
  261. VOID vI32ColorPatternTrapezoid(
  262. TRAPEZOIDDATA* ptd,
  263. LONG yTrapezoid,
  264. LONG cyTrapezoid)
  265. {
  266. PDEV* ppdev;
  267. BYTE* pjIoBase;
  268. LONG xOffset;
  269. LONG lLeftError;
  270. LONG xLeft;
  271. LONG lRightError;
  272. LONG xRight;
  273. LONG lTmp;
  274. EDGEDATA edTmp;
  275. BYTE* pjPatternStart;
  276. WORD* pwPattern;
  277. LONG xBrush;
  278. LONG yPattern;
  279. LONG cyRoll;
  280. ppdev = ptd->ppdev;
  281. pjIoBase = ppdev->pjIoBase;
  282. xOffset = ppdev->xOffset;
  283. yTrapezoid += ppdev->yOffset;
  284. pjPatternStart = (BYTE*) &ptd->prb->aulPattern[0];
  285. // xBrush needs to be shifted by DFB alignment.
  286. xBrush = ptd->ptlBrush.x + xOffset;
  287. // yTrapezoid has alread been aligned, but yPattern should _NOT_ be.
  288. yPattern = yTrapezoid - ptd->ptlBrush.y - ppdev->yOffset;
  289. lLeftError = ptd->aed[LEFT].lError;
  290. xLeft = ptd->aed[LEFT].x + xOffset;
  291. lRightError = ptd->aed[RIGHT].lError;
  292. xRight = ptd->aed[RIGHT].x + xOffset;
  293. // If the left and right edges are vertical, simply output as
  294. // a rectangle:
  295. cyRoll = 0;
  296. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  297. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0) &&
  298. (cyTrapezoid > 8) &&
  299. (ptd->bOverpaint))
  300. {
  301. /////////////////////////////////////////////////////////////////
  302. // Vertical-edge special case
  303. cyRoll = cyTrapezoid - 8;
  304. cyTrapezoid = 8;
  305. }
  306. while (TRUE)
  307. {
  308. /////////////////////////////////////////////////////////////////
  309. // Run the DDAs
  310. if (xLeft < xRight)
  311. {
  312. pwPattern = (WORD*) (pjPatternStart + ((yPattern & 7) << 3));
  313. yPattern++;
  314. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 9);
  315. I32_OW(pjIoBase, PATT_INDEX, (xLeft - xBrush) & 7);
  316. I32_OW(pjIoBase, CUR_X, xLeft);
  317. I32_OW(pjIoBase, DEST_X_END, xRight);
  318. I32_OW(pjIoBase, PATT_DATA_INDEX, 0);
  319. I32_OW(pjIoBase, PATT_DATA, *(pwPattern));
  320. I32_OW(pjIoBase, PATT_DATA, *(pwPattern + 1));
  321. I32_OW(pjIoBase, PATT_DATA, *(pwPattern + 2));
  322. I32_OW(pjIoBase, PATT_DATA, *(pwPattern + 3));
  323. yTrapezoid++;
  324. I32_OW(pjIoBase, DEST_Y_END, yTrapezoid);
  325. }
  326. else if (xLeft > xRight)
  327. {
  328. // We don't bother optimizing this case because we should
  329. // rarely get self-intersecting polygons (if we're slow,
  330. // the app gets what it deserves).
  331. SWAP(xLeft, xRight, lTmp);
  332. SWAP(lLeftError, lRightError, lTmp);
  333. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  334. continue;
  335. }
  336. else
  337. {
  338. yTrapezoid++;
  339. yPattern++;
  340. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 1);
  341. I32_OW(pjIoBase, CUR_Y, yTrapezoid);
  342. }
  343. // Advance the right wall:
  344. xRight += ptd->aed[RIGHT].dx;
  345. lRightError += ptd->aed[RIGHT].lErrorUp;
  346. if (lRightError >= 0)
  347. {
  348. lRightError -= ptd->aed[RIGHT].dN;
  349. xRight++;
  350. }
  351. // Advance the left wall:
  352. xLeft += ptd->aed[LEFT].dx;
  353. lLeftError += ptd->aed[LEFT].lErrorUp;
  354. if (lLeftError >= 0)
  355. {
  356. lLeftError -= ptd->aed[LEFT].dN;
  357. xLeft++;
  358. }
  359. cyTrapezoid--;
  360. if (cyTrapezoid == 0)
  361. break;
  362. }
  363. // The above has already insured that xLeft <= xRight for the vertical
  364. // edge case, but we still have to make sure it's not an empty
  365. // rectangle:
  366. if (cyRoll > 0)
  367. {
  368. if (xLeft < xRight)
  369. {
  370. // When the ROP is PATCOPY, we take advantage of the fact that
  371. // we've just laid down an entire row of the pattern, and can
  372. // do a 'rolling' screen-to-screen blt to draw the rest.
  373. //
  374. // What's interesting about this case is that sometimes this will
  375. // be done when a clipping rectangle has been set using the
  376. // hardware clip registers. Fortunately, it's not a problem: we
  377. // started drawing at prclClip->top, which means we're assured we
  378. // won't try to replicate any vertical part that has been clipped
  379. // out; and the left and right edges aren't a problem because the
  380. // same clipping applies to this rolled part.
  381. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 11);
  382. I32_OW(pjIoBase, DP_CONFIG, FG_COLOR_SRC_BLIT | DATA_WIDTH |
  383. DRAW | DATA_ORDER | WRITE);
  384. I32_OW(pjIoBase, CUR_X, xLeft);
  385. I32_OW(pjIoBase, DEST_X_START, xLeft);
  386. I32_OW(pjIoBase, M32_SRC_X, xLeft);
  387. I32_OW(pjIoBase, M32_SRC_X_START, xLeft);
  388. I32_OW(pjIoBase, M32_SRC_X_END, xRight);
  389. I32_OW(pjIoBase, DEST_X_END, xRight);
  390. I32_OW(pjIoBase, M32_SRC_Y, yTrapezoid - 8);
  391. I32_OW(pjIoBase, CUR_Y, yTrapezoid);
  392. I32_OW(pjIoBase, DEST_Y_END, yTrapezoid + cyRoll);
  393. // Restore config register to default state for next trapezoid:
  394. I32_OW(pjIoBase, DP_CONFIG, FG_COLOR_SRC_PATT | DATA_WIDTH |
  395. DRAW | WRITE);
  396. }
  397. else
  398. {
  399. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 1);
  400. I32_OW(pjIoBase, CUR_Y, yTrapezoid + cyRoll);
  401. }
  402. }
  403. ptd->aed[LEFT].lError = lLeftError;
  404. ptd->aed[LEFT].x = xLeft - xOffset;
  405. ptd->aed[RIGHT].lError = lRightError;
  406. ptd->aed[RIGHT].x = xRight - xOffset;
  407. }
  408. /******************************Public*Routine******************************\
  409. * VOID vI32TrapezoidSetup
  410. *
  411. * Initialize the hardware and some state for doing trapezoids.
  412. *
  413. \**************************************************************************/
  414. VOID vI32TrapezoidSetup(
  415. PDEV* ppdev,
  416. ULONG rop4,
  417. ULONG iSolidColor,
  418. RBRUSH* prb,
  419. POINTL* pptlBrush,
  420. TRAPEZOIDDATA* ptd,
  421. LONG yStart, // First scan for drawing
  422. RECTL* prclClip) // NULL if no clipping
  423. {
  424. BYTE* pjIoBase;
  425. ULONG ulHwForeMix;
  426. LONG xOffset;
  427. pjIoBase = ppdev->pjIoBase;
  428. ptd->ppdev = ppdev;
  429. ulHwForeMix = gaul32HwMixFromRop2[(rop4 >> 2) & 0xf];
  430. if ((prclClip != NULL) && (prclClip->top > yStart))
  431. yStart = prclClip->top;
  432. if (iSolidColor != -1)
  433. {
  434. /////////////////////////////////////////////////////////////////
  435. // Setup for solid colours
  436. ptd->pfnTrap = vI32SolidTrapezoid;
  437. // We initialize the hardware for the colour, mix, pixel operation,
  438. // and the y position for the first scan:
  439. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 5);
  440. I32_OW(pjIoBase, FRGD_COLOR, iSolidColor);
  441. I32_OW(pjIoBase, ALU_FG_FN, ulHwForeMix);
  442. I32_OW(pjIoBase, DP_CONFIG, FG_COLOR_SRC_FG | WRITE | DRAW);
  443. I32_OW(pjIoBase, CUR_Y, yStart + ppdev->yOffset);
  444. // Even though we will be drawing one-scan high rectangles and
  445. // theoretically don't need to set DEST_X_START, it turns out
  446. // that we have to make sure this value is less than DEST_X_END,
  447. // otherwise the rectangle is drawn in the wrong direction...
  448. I32_OW(pjIoBase, DEST_X_START, 0);
  449. }
  450. else
  451. {
  452. ASSERTDD(!(prb->fl & RBRUSH_2COLOR), "Can't handle monchrome for now");
  453. /////////////////////////////////////////////////////////////////
  454. // Setup for patterns
  455. ptd->pfnTrap = vI32ColorPatternTrapezoid;
  456. ptd->prb = prb;
  457. ptd->bOverpaint = (ulHwForeMix == OVERPAINT);
  458. ptd->ptlBrush.x = pptlBrush->x;
  459. ptd->ptlBrush.y = pptlBrush->y;
  460. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 6);
  461. I32_OW(pjIoBase, ALU_FG_FN, ulHwForeMix);
  462. I32_OW(pjIoBase, SRC_Y_DIR, 1);
  463. I32_OW(pjIoBase, DP_CONFIG, FG_COLOR_SRC_PATT | DATA_WIDTH |
  464. DRAW | WRITE);
  465. I32_OW(pjIoBase, PATT_LENGTH, 7);
  466. I32_OW(pjIoBase, CUR_Y, yStart + ppdev->yOffset);
  467. I32_OW(pjIoBase, DEST_X_START, 0); // See note above...
  468. }
  469. if (prclClip != NULL)
  470. {
  471. ptd->pfnTrapClip = ptd->pfnTrap;
  472. ptd->pfnTrap = vClipTrapezoid;
  473. ptd->yClipTop = prclClip->top;
  474. ptd->yClipBottom = prclClip->bottom;
  475. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 2);
  476. xOffset = ppdev->xOffset;
  477. I32_OW(pjIoBase, EXT_SCISSOR_L, xOffset + prclClip->left);
  478. I32_OW(pjIoBase, EXT_SCISSOR_R, xOffset + prclClip->right - 1);
  479. }
  480. }
  481. /******************************Public*Routine******************************\
  482. * VOID vM32SolidTrapezoid
  483. *
  484. * Draws a solid trapezoid using a software DDA.
  485. *
  486. \**************************************************************************/
  487. VOID vM32SolidTrapezoid(
  488. TRAPEZOIDDATA* ptd,
  489. LONG yTrapezoid,
  490. LONG cyTrapezoid)
  491. {
  492. PDEV* ppdev;
  493. BYTE* pjMmBase;
  494. LONG xOffset;
  495. LONG lLeftError;
  496. LONG xLeft;
  497. LONG lRightError;
  498. LONG xRight;
  499. LONG lTmp;
  500. EDGEDATA edTmp;
  501. // Note that CUR_Y is already set...
  502. ppdev = ptd->ppdev;
  503. pjMmBase = ppdev->pjMmBase;
  504. xOffset = ppdev->xOffset;
  505. yTrapezoid += ppdev->yOffset;
  506. // If the left and right edges are vertical, simply output as
  507. // a rectangle:
  508. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  509. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  510. {
  511. /////////////////////////////////////////////////////////////////
  512. // Vertical-edge special case
  513. xLeft = ptd->aed[LEFT].x + xOffset;
  514. xRight = ptd->aed[RIGHT].x + xOffset;
  515. if (xLeft > xRight)
  516. {
  517. SWAP(xLeft, xRight, lTmp);
  518. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  519. }
  520. if (xLeft < xRight)
  521. {
  522. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 4);
  523. M32_OW(pjMmBase, CUR_X, xLeft);
  524. M32_OW(pjMmBase, DEST_X_START, xLeft);
  525. M32_OW(pjMmBase, DEST_X_END, xRight);
  526. M32_OW(pjMmBase, DEST_Y_END, yTrapezoid + cyTrapezoid);
  527. }
  528. else
  529. {
  530. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  531. M32_OW(pjMmBase, CUR_Y, yTrapezoid + cyTrapezoid);
  532. }
  533. }
  534. else
  535. {
  536. lLeftError = ptd->aed[LEFT].lError;
  537. xLeft = ptd->aed[LEFT].x + xOffset;
  538. lRightError = ptd->aed[RIGHT].lError;
  539. xRight = ptd->aed[RIGHT].x + xOffset;
  540. while (TRUE)
  541. {
  542. /////////////////////////////////////////////////////////////////
  543. // Run the DDAs
  544. if (xLeft < xRight)
  545. {
  546. // Note that we don't need to set DEST_X_START because
  547. // we're always doing blts that are only one scan high.
  548. //
  549. // The ATI is nice enough to always automatically advance
  550. // CUR_Y to become DEST_Y_END after the blt is done, so we
  551. // never have to update it:
  552. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
  553. M32_OW(pjMmBase, CUR_X, xLeft);
  554. M32_OW(pjMmBase, DEST_X_END, xRight);
  555. yTrapezoid++;
  556. M32_OW(pjMmBase, DEST_Y_END, yTrapezoid);
  557. }
  558. else if (xLeft > xRight)
  559. {
  560. // We don't bother optimizing this case because we should
  561. // rarely get self-intersecting polygons (if we're slow,
  562. // the app gets what it deserves).
  563. SWAP(xLeft, xRight, lTmp);
  564. SWAP(lLeftError, lRightError, lTmp);
  565. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  566. continue;
  567. }
  568. else
  569. {
  570. yTrapezoid++;
  571. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  572. M32_OW(pjMmBase, CUR_Y, yTrapezoid);
  573. }
  574. // Advance the right wall:
  575. xRight += ptd->aed[RIGHT].dx;
  576. lRightError += ptd->aed[RIGHT].lErrorUp;
  577. if (lRightError >= 0)
  578. {
  579. lRightError -= ptd->aed[RIGHT].dN;
  580. xRight++;
  581. }
  582. // Advance the left wall:
  583. xLeft += ptd->aed[LEFT].dx;
  584. lLeftError += ptd->aed[LEFT].lErrorUp;
  585. if (lLeftError >= 0)
  586. {
  587. lLeftError -= ptd->aed[LEFT].dN;
  588. xLeft++;
  589. }
  590. cyTrapezoid--;
  591. if (cyTrapezoid == 0)
  592. break;
  593. }
  594. ptd->aed[LEFT].lError = lLeftError;
  595. ptd->aed[LEFT].x = xLeft - xOffset;
  596. ptd->aed[RIGHT].lError = lRightError;
  597. ptd->aed[RIGHT].x = xRight - xOffset;
  598. }
  599. }
  600. /******************************Public*Routine******************************\
  601. * VOID vM32ColorPatternTrapezoid
  602. *
  603. * Draws a patterned trapezoid using a software DDA.
  604. *
  605. \**************************************************************************/
  606. VOID vM32ColorPatternTrapezoid(
  607. TRAPEZOIDDATA* ptd,
  608. LONG yTrapezoid,
  609. LONG cyTrapezoid)
  610. {
  611. PDEV* ppdev;
  612. BYTE* pjMmBase;
  613. LONG xOffset;
  614. LONG lLeftError;
  615. LONG xLeft;
  616. LONG lRightError;
  617. LONG xRight;
  618. LONG lTmp;
  619. EDGEDATA edTmp;
  620. BYTE* pjPatternStart;
  621. WORD* pwPattern;
  622. LONG xBrush;
  623. LONG yPattern;
  624. LONG cyRoll;
  625. ppdev = ptd->ppdev;
  626. pjMmBase = ppdev->pjMmBase;
  627. xOffset = ppdev->xOffset;
  628. yTrapezoid += ppdev->yOffset;
  629. pjPatternStart = (BYTE*) &ptd->prb->aulPattern[0];
  630. // xBrush needs to be shifted by DFB alignment.
  631. xBrush = ptd->ptlBrush.x + xOffset;
  632. // yTrapezoid has already been aligned, but yPattern should _NOT_ be.
  633. yPattern = yTrapezoid - ptd->ptlBrush.y - ppdev->yOffset;
  634. lLeftError = ptd->aed[LEFT].lError;
  635. xLeft = ptd->aed[LEFT].x + xOffset;
  636. lRightError = ptd->aed[RIGHT].lError;
  637. xRight = ptd->aed[RIGHT].x + xOffset;
  638. // If the left and right edges are vertical, simply output as
  639. // a rectangle:
  640. cyRoll = 0;
  641. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  642. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0) &&
  643. (cyTrapezoid > 8) &&
  644. (ptd->bOverpaint))
  645. {
  646. /////////////////////////////////////////////////////////////////
  647. // Vertical-edge special case
  648. cyRoll = cyTrapezoid - 8;
  649. cyTrapezoid = 8;
  650. }
  651. while (TRUE)
  652. {
  653. /////////////////////////////////////////////////////////////////
  654. // Run the DDAs
  655. if (xLeft < xRight)
  656. {
  657. pwPattern = (WORD*) (pjPatternStart + ((yPattern & 7) << 3));
  658. yPattern++;
  659. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 9);
  660. M32_OW(pjMmBase, PATT_INDEX, (xLeft - xBrush) & 7);
  661. M32_OW(pjMmBase, CUR_X, xLeft);
  662. M32_OW(pjMmBase, DEST_X_END, xRight);
  663. M32_OW(pjMmBase, PATT_DATA_INDEX, 0);
  664. M32_OW(pjMmBase, PATT_DATA, *(pwPattern));
  665. M32_OW(pjMmBase, PATT_DATA, *(pwPattern + 1));
  666. M32_OW(pjMmBase, PATT_DATA, *(pwPattern + 2));
  667. M32_OW(pjMmBase, PATT_DATA, *(pwPattern + 3));
  668. yTrapezoid++;
  669. M32_OW(pjMmBase, DEST_Y_END, yTrapezoid);
  670. }
  671. else if (xLeft > xRight)
  672. {
  673. // We don't bother optimizing this case because we should
  674. // rarely get self-intersecting polygons (if we're slow,
  675. // the app gets what it deserves).
  676. SWAP(xLeft, xRight, lTmp);
  677. SWAP(lLeftError, lRightError, lTmp);
  678. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  679. continue;
  680. }
  681. else
  682. {
  683. yTrapezoid++;
  684. yPattern++;
  685. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  686. M32_OW(pjMmBase, CUR_Y, yTrapezoid);
  687. }
  688. // Advance the right wall:
  689. xRight += ptd->aed[RIGHT].dx;
  690. lRightError += ptd->aed[RIGHT].lErrorUp;
  691. if (lRightError >= 0)
  692. {
  693. lRightError -= ptd->aed[RIGHT].dN;
  694. xRight++;
  695. }
  696. // Advance the left wall:
  697. xLeft += ptd->aed[LEFT].dx;
  698. lLeftError += ptd->aed[LEFT].lErrorUp;
  699. if (lLeftError >= 0)
  700. {
  701. lLeftError -= ptd->aed[LEFT].dN;
  702. xLeft++;
  703. }
  704. cyTrapezoid--;
  705. if (cyTrapezoid == 0)
  706. break;
  707. }
  708. // The above has already insured that xLeft <= xRight for the vertical
  709. // edge case, but we still have to make sure it's not an empty
  710. // rectangle:
  711. if (cyRoll > 0)
  712. {
  713. if (xLeft < xRight)
  714. {
  715. // When the ROP is PATCOPY, we take advantage of the fact that
  716. // we've just laid down an entire row of the pattern, and can
  717. // do a 'rolling' screen-to-screen blt to draw the rest.
  718. //
  719. // What's interesting about this case is that sometimes this will
  720. // be done when a clipping rectangle has been set using the
  721. // hardware clip registers. Fortunately, it's not a problem: we
  722. // started drawing at prclClip->top, which means we're assured we
  723. // won't try to replicate any vertical part that has been clipped
  724. // out; and the left and right edges aren't a problem because the
  725. // same clipping applies to this rolled part.
  726. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 11);
  727. M32_OW(pjMmBase, DP_CONFIG, FG_COLOR_SRC_BLIT | DATA_WIDTH |
  728. DRAW | DATA_ORDER | WRITE);
  729. M32_OW(pjMmBase, CUR_X, xLeft);
  730. M32_OW(pjMmBase, DEST_X_START, xLeft);
  731. M32_OW(pjMmBase, M32_SRC_X, xLeft);
  732. M32_OW(pjMmBase, M32_SRC_X_START, xLeft);
  733. M32_OW(pjMmBase, M32_SRC_X_END, xRight);
  734. M32_OW(pjMmBase, DEST_X_END, xRight);
  735. M32_OW(pjMmBase, M32_SRC_Y, yTrapezoid - 8);
  736. M32_OW(pjMmBase, CUR_Y, yTrapezoid);
  737. M32_OW(pjMmBase, DEST_Y_END, yTrapezoid + cyRoll);
  738. // Restore config register to default state for next trapezoid:
  739. M32_OW(pjMmBase, DP_CONFIG, FG_COLOR_SRC_PATT | DATA_WIDTH |
  740. DRAW | WRITE);
  741. }
  742. else
  743. {
  744. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  745. M32_OW(pjMmBase, CUR_Y, yTrapezoid + cyRoll);
  746. }
  747. }
  748. ptd->aed[LEFT].lError = lLeftError;
  749. ptd->aed[LEFT].x = xLeft - xOffset;
  750. ptd->aed[RIGHT].lError = lRightError;
  751. ptd->aed[RIGHT].x = xRight - xOffset;
  752. }
  753. /******************************Public*Routine******************************\
  754. * VOID vM32TrapezoidSetup
  755. *
  756. * Initialize the hardware and some state for doing trapezoids.
  757. *
  758. \**************************************************************************/
  759. VOID vM32TrapezoidSetup(
  760. PDEV* ppdev,
  761. ULONG rop4,
  762. ULONG iSolidColor,
  763. RBRUSH* prb,
  764. POINTL* pptlBrush,
  765. TRAPEZOIDDATA* ptd,
  766. LONG yStart, // First scan for drawing
  767. RECTL* prclClip) // NULL if no clipping
  768. {
  769. BYTE* pjMmBase;
  770. ULONG ulHwForeMix;
  771. LONG xOffset;
  772. pjMmBase = ppdev->pjMmBase;
  773. ptd->ppdev = ppdev;
  774. ulHwForeMix = gaul32HwMixFromRop2[(rop4 >> 2) & 0xf];
  775. if ((prclClip != NULL) && (prclClip->top > yStart))
  776. yStart = prclClip->top;
  777. if (iSolidColor != -1)
  778. {
  779. /////////////////////////////////////////////////////////////////
  780. // Setup for solid colours
  781. ptd->pfnTrap = vM32SolidTrapezoid;
  782. // We initialize the hardware for the colour, mix, pixel operation,
  783. // and the y position for the first scan:
  784. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
  785. M32_OW(pjMmBase, FRGD_COLOR, iSolidColor);
  786. M32_OW(pjMmBase, ALU_FG_FN, ulHwForeMix);
  787. M32_OW(pjMmBase, DP_CONFIG, FG_COLOR_SRC_FG | WRITE | DRAW);
  788. M32_OW(pjMmBase, CUR_Y, yStart + ppdev->yOffset);
  789. // Even though we will be drawing one-scan high rectangles and
  790. // theoretically don't need to set DEST_X_START, it turns out
  791. // that we have to make sure this value is less than DEST_X_END,
  792. // otherwise the rectangle is drawn in the wrong direction...
  793. M32_OW(pjMmBase, DEST_X_START, 0);
  794. }
  795. else
  796. {
  797. ASSERTDD(!(prb->fl & RBRUSH_2COLOR), "Can't handle monchrome for now");
  798. /////////////////////////////////////////////////////////////////
  799. // Setup for patterns
  800. ptd->pfnTrap = vM32ColorPatternTrapezoid;
  801. ptd->prb = prb;
  802. ptd->bOverpaint = (ulHwForeMix == OVERPAINT);
  803. ptd->ptlBrush.x = pptlBrush->x;
  804. ptd->ptlBrush.y = pptlBrush->y;
  805. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 6);
  806. M32_OW(pjMmBase, ALU_FG_FN, ulHwForeMix);
  807. M32_OW(pjMmBase, SRC_Y_DIR, 1);
  808. M32_OW(pjMmBase, DP_CONFIG, FG_COLOR_SRC_PATT | DATA_WIDTH |
  809. DRAW | WRITE);
  810. M32_OW(pjMmBase, PATT_LENGTH, 7);
  811. M32_OW(pjMmBase, CUR_Y, yStart + ppdev->yOffset);
  812. M32_OW(pjMmBase, DEST_X_START, 0); // See note above...
  813. }
  814. if (prclClip != NULL)
  815. {
  816. ptd->pfnTrapClip = ptd->pfnTrap;
  817. ptd->pfnTrap = vClipTrapezoid;
  818. ptd->yClipTop = prclClip->top;
  819. ptd->yClipBottom = prclClip->bottom;
  820. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 2);
  821. xOffset = ppdev->xOffset;
  822. M32_OW(pjMmBase, EXT_SCISSOR_L, xOffset + prclClip->left);
  823. M32_OW(pjMmBase, EXT_SCISSOR_R, xOffset + prclClip->right - 1);
  824. }
  825. }
  826. /******************************Public*Routine******************************\
  827. * VOID vM64SolidTrapezoid
  828. *
  829. * Draws a solid trapezoid using a software DDA.
  830. *
  831. \**************************************************************************/
  832. VOID vM64SolidTrapezoid(
  833. TRAPEZOIDDATA* ptd,
  834. LONG yTrapezoid,
  835. LONG cyTrapezoid)
  836. {
  837. PDEV* ppdev;
  838. BYTE* pjMmBase;
  839. LONG xOffset;
  840. LONG lLeftError;
  841. LONG xLeft;
  842. LONG lRightError;
  843. LONG xRight;
  844. LONG lTmp;
  845. EDGEDATA edTmp;
  846. ULONG ulFifo;
  847. ppdev = ptd->ppdev;
  848. pjMmBase = ppdev->pjMmBase;
  849. xOffset = ppdev->xOffset;
  850. yTrapezoid += ppdev->yOffset;
  851. // If the left and right edges are vertical, simply output as
  852. // a rectangle:
  853. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  854. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  855. {
  856. /////////////////////////////////////////////////////////////////
  857. // Vertical-edge special case
  858. xLeft = ptd->aed[LEFT].x + xOffset;
  859. xRight = ptd->aed[RIGHT].x + xOffset;
  860. if (xLeft > xRight)
  861. {
  862. SWAP(xLeft, xRight, lTmp);
  863. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  864. }
  865. if (xLeft < xRight)
  866. {
  867. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
  868. // Note that 'x' can be negative, but we can still use
  869. // 'PACKXY_FAST' because 'y' can't be negative:
  870. M64_OD(pjMmBase, DST_X, xLeft);
  871. M64_OD(pjMmBase, DST_HEIGHT_WIDTH, PACKXY_FAST(xRight - xLeft,
  872. cyTrapezoid));
  873. M64_OD(pjMmBase, DST_HEIGHT, 1);
  874. }
  875. else
  876. {
  877. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  878. M64_OD(pjMmBase, DST_Y, yTrapezoid + cyTrapezoid);
  879. }
  880. }
  881. else
  882. {
  883. yTrapezoid += cyTrapezoid + 1; // One past end scan
  884. lLeftError = ptd->aed[LEFT].lError;
  885. xLeft = ptd->aed[LEFT].x + xOffset;
  886. lRightError = ptd->aed[RIGHT].lError;
  887. xRight = ptd->aed[RIGHT].x + xOffset;
  888. ulFifo = 0; // Don't forget to initialize
  889. while (TRUE)
  890. {
  891. /////////////////////////////////////////////////////////////////
  892. // Run the DDAs
  893. if (xLeft < xRight)
  894. {
  895. M64_FAST_FIFO_CHECK(ppdev, pjMmBase, 2, ulFifo);
  896. M64_OD(pjMmBase, DST_X, xLeft);
  897. M64_OD(pjMmBase, DST_WIDTH, xRight - xLeft);
  898. }
  899. else if (xLeft > xRight)
  900. {
  901. // We don't bother optimizing this case because we should
  902. // rarely get self-intersecting polygons (if we're slow,
  903. // the app gets what it deserves).
  904. SWAP(xLeft, xRight, lTmp);
  905. SWAP(lLeftError, lRightError, lTmp);
  906. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  907. continue;
  908. }
  909. else
  910. {
  911. M64_FAST_FIFO_CHECK(ppdev, pjMmBase, 1, ulFifo);
  912. M64_OD(pjMmBase, DST_Y, yTrapezoid - cyTrapezoid);
  913. }
  914. // Advance the right wall:
  915. xRight += ptd->aed[RIGHT].dx;
  916. lRightError += ptd->aed[RIGHT].lErrorUp;
  917. if (lRightError >= 0)
  918. {
  919. lRightError -= ptd->aed[RIGHT].dN;
  920. xRight++;
  921. }
  922. // Advance the left wall:
  923. xLeft += ptd->aed[LEFT].dx;
  924. lLeftError += ptd->aed[LEFT].lErrorUp;
  925. if (lLeftError >= 0)
  926. {
  927. lLeftError -= ptd->aed[LEFT].dN;
  928. xLeft++;
  929. }
  930. cyTrapezoid--;
  931. if (cyTrapezoid == 0)
  932. break;
  933. }
  934. ptd->aed[LEFT].lError = lLeftError;
  935. ptd->aed[LEFT].x = xLeft - xOffset;
  936. ptd->aed[RIGHT].lError = lRightError;
  937. ptd->aed[RIGHT].x = xRight - xOffset;
  938. }
  939. }
  940. /******************************Public*Routine******************************\
  941. * VOID vM64ColorPatternTrapezoid
  942. *
  943. * Draws a patterned trapezoid using a software DDA.
  944. *
  945. \**************************************************************************/
  946. VOID vM64ColorPatternTrapezoid(
  947. TRAPEZOIDDATA* ptd,
  948. LONG yTrapezoid,
  949. LONG cyTrapezoid)
  950. {
  951. PDEV* ppdev;
  952. BYTE* pjMmBase;
  953. LONG yPattern;
  954. LONG xBrush;
  955. LONG xOffset;
  956. LONG lLeftError;
  957. LONG xLeft;
  958. LONG lRightError;
  959. LONG xRight;
  960. LONG lTmp;
  961. EDGEDATA edTmp;
  962. ULONG ulSrc;
  963. ULONG ulFifo;
  964. ppdev = ptd->ppdev;
  965. pjMmBase = ppdev->pjMmBase;
  966. yPattern = (yTrapezoid - ptd->ptlBrush.y) & 7; // Must normalize for later
  967. xBrush = ptd->ptlBrush.x;
  968. xOffset = ppdev->xOffset;
  969. yTrapezoid += ppdev->yOffset;
  970. // If the left and right edges are vertical, simply output as
  971. // a rectangle:
  972. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  973. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  974. {
  975. /////////////////////////////////////////////////////////////////
  976. // Vertical-edge special case
  977. xLeft = ptd->aed[LEFT].x + xOffset;
  978. xRight = ptd->aed[RIGHT].x + xOffset;
  979. if (xLeft > xRight)
  980. {
  981. SWAP(xLeft, xRight, lTmp);
  982. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  983. }
  984. if (xLeft < xRight)
  985. {
  986. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
  987. ulSrc = PACKXY_FAST(xLeft - xBrush, yPattern) & 0x70007;
  988. M64_OD(pjMmBase, SRC_Y_X, ulSrc);
  989. M64_OD(pjMmBase, SRC_HEIGHT1_WIDTH1, 0x80008 - ulSrc);
  990. M64_OD(pjMmBase, DST_X, xLeft);
  991. M64_OD(pjMmBase, DST_HEIGHT_WIDTH, PACKXY_FAST(xRight - xLeft,
  992. cyTrapezoid));
  993. M64_OD(pjMmBase, DST_HEIGHT, 1);
  994. }
  995. else
  996. {
  997. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
  998. M64_OD(pjMmBase, DST_Y, yTrapezoid + cyTrapezoid);
  999. }
  1000. }
  1001. else
  1002. {
  1003. yTrapezoid += cyTrapezoid + 1; // One past end scan
  1004. lLeftError = ptd->aed[LEFT].lError;
  1005. xLeft = ptd->aed[LEFT].x + xOffset;
  1006. lRightError = ptd->aed[RIGHT].lError;
  1007. xRight = ptd->aed[RIGHT].x + xOffset;
  1008. ulFifo = 0; // Don't forget to initialize
  1009. while (TRUE)
  1010. {
  1011. /////////////////////////////////////////////////////////////////
  1012. // Run the DDAs
  1013. if (xLeft < xRight)
  1014. {
  1015. M64_FAST_FIFO_CHECK(ppdev, pjMmBase, 4, ulFifo);
  1016. // Note that we can use PACKXY_FAST because 'yPattern' will
  1017. // never overflow 16 bits:
  1018. ulSrc = PACKXY_FAST(xLeft - xBrush, yPattern) & 0x70007;
  1019. yPattern++;
  1020. M64_OD(pjMmBase, SRC_Y_X, ulSrc);
  1021. M64_OD(pjMmBase, SRC_HEIGHT1_WIDTH1, 0x80008 - ulSrc);
  1022. M64_OD(pjMmBase, DST_X, xLeft);
  1023. M64_OD(pjMmBase, DST_WIDTH, xRight - xLeft);
  1024. }
  1025. else if (xLeft > xRight)
  1026. {
  1027. // We don't bother optimizing this case because we should
  1028. // rarely get self-intersecting polygons (if we're slow,
  1029. // the app gets what it deserves).
  1030. SWAP(xLeft, xRight, lTmp);
  1031. SWAP(lLeftError, lRightError, lTmp);
  1032. SWAP(ptd->aed[LEFT], ptd->aed[RIGHT], edTmp);
  1033. continue;
  1034. }
  1035. else
  1036. {
  1037. M64_FAST_FIFO_CHECK(ppdev, pjMmBase, 1, ulFifo);
  1038. M64_OD(pjMmBase, DST_Y, yTrapezoid - cyTrapezoid);
  1039. yPattern++;
  1040. }
  1041. // Advance the right wall:
  1042. xRight += ptd->aed[RIGHT].dx;
  1043. lRightError += ptd->aed[RIGHT].lErrorUp;
  1044. if (lRightError >= 0)
  1045. {
  1046. lRightError -= ptd->aed[RIGHT].dN;
  1047. xRight++;
  1048. }
  1049. // Advance the left wall:
  1050. xLeft += ptd->aed[LEFT].dx;
  1051. lLeftError += ptd->aed[LEFT].lErrorUp;
  1052. if (lLeftError >= 0)
  1053. {
  1054. lLeftError -= ptd->aed[LEFT].dN;
  1055. xLeft++;
  1056. }
  1057. cyTrapezoid--;
  1058. if (cyTrapezoid == 0)
  1059. break;
  1060. }
  1061. ptd->aed[LEFT].lError = lLeftError;
  1062. ptd->aed[LEFT].x = xLeft - xOffset;
  1063. ptd->aed[RIGHT].lError = lRightError;
  1064. ptd->aed[RIGHT].x = xRight - xOffset;
  1065. }
  1066. }
  1067. /******************************Public*Routine******************************\
  1068. * VOID vM64TrapezoidSetup
  1069. *
  1070. * Initialize the hardware and some state for doing trapezoids.
  1071. *
  1072. \**************************************************************************/
  1073. VOID vM64TrapezoidSetup(
  1074. PDEV* ppdev,
  1075. ULONG rop4,
  1076. ULONG iSolidColor,
  1077. RBRUSH* prb,
  1078. POINTL* pptlBrush,
  1079. TRAPEZOIDDATA* ptd,
  1080. LONG yStart, // First scan for drawing
  1081. RECTL* prclClip) // NULL if no clipping
  1082. {
  1083. BYTE* pjMmBase;
  1084. BRUSHENTRY* pbe;
  1085. LONG xOffset;
  1086. pjMmBase = ppdev->pjMmBase;
  1087. ptd->ppdev = ppdev;
  1088. if ((prclClip != NULL) && (prclClip->top > yStart))
  1089. yStart = prclClip->top;
  1090. if (iSolidColor != -1)
  1091. {
  1092. /////////////////////////////////////////////////////////////////
  1093. // Setup for solid colours
  1094. ptd->pfnTrap = vM64SolidTrapezoid;
  1095. // We initialize the hardware for the colour, mix, pixel operation,
  1096. // and the y position for the first scan:
  1097. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 7); // Don't forget SC_LEFT_RIGHT
  1098. //M64_OD(pjMmBase, CONTEXT_LOAD_CNTL, CONTEXT_LOAD_CmdLoad | ppdev->iDefContext );
  1099. M64_OD(pjMmBase, DP_FRGD_CLR, iSolidColor);
  1100. M64_OD(pjMmBase, DP_SRC, DP_SRC_FrgdClr << 8);
  1101. }
  1102. else
  1103. {
  1104. ASSERTDD(!(prb->fl & RBRUSH_2COLOR), "Can't handle monchrome for now");
  1105. /////////////////////////////////////////////////////////////////
  1106. // Setup for patterns
  1107. ptd->pfnTrap = vM64ColorPatternTrapezoid;
  1108. ptd->ptlBrush.x = pptlBrush->x;
  1109. ptd->ptlBrush.y = pptlBrush->y;
  1110. // See if the brush has already been put into off-screen memory:
  1111. pbe = prb->apbe[IBOARD(ppdev)];
  1112. if ((pbe == NULL) || (pbe->prbVerify != prb))
  1113. {
  1114. vM64PatColorRealize(ppdev, prb);
  1115. pbe = prb->apbe[IBOARD(ppdev)];
  1116. }
  1117. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 10); // Don't forget SC_LEFT_RIGHT
  1118. //M64_OD(pjMmBase, CONTEXT_LOAD_CNTL, CONTEXT_LOAD_CmdLoad | ppdev->iDefContext );
  1119. M64_OD(pjMmBase, SRC_OFF_PITCH, pbe->ulOffsetPitch);
  1120. M64_OD(pjMmBase, SRC_CNTL, SRC_CNTL_PatEna | SRC_CNTL_PatRotEna);
  1121. M64_OD(pjMmBase, DP_SRC, DP_SRC_Blit << 8);
  1122. M64_OD(pjMmBase, SRC_Y_X_START, 0);
  1123. M64_OD(pjMmBase, SRC_HEIGHT2_WIDTH2, PACKXY(8, 8));
  1124. }
  1125. // We could make set DST_CNTL_YTile in the default state for DST_CNTL,
  1126. // and thus save ourselves a write:
  1127. M64_OD(pjMmBase, DP_MIX, gaul64HwMixFromRop2[(rop4 >> 2) & 0xf]);
  1128. M64_OD(pjMmBase, DST_Y, yStart + ppdev->yOffset);
  1129. M64_OD(pjMmBase, DST_HEIGHT, 1);
  1130. M64_OD(pjMmBase, DST_CNTL, DST_CNTL_XDir | DST_CNTL_YDir |
  1131. DST_CNTL_YTile);
  1132. if (prclClip != NULL)
  1133. {
  1134. ptd->pfnTrapClip = ptd->pfnTrap;
  1135. ptd->pfnTrap = vClipTrapezoid;
  1136. ptd->yClipTop = prclClip->top;
  1137. ptd->yClipBottom = prclClip->bottom;
  1138. xOffset = ppdev->xOffset;
  1139. M64_OD(pjMmBase, SC_LEFT_RIGHT, PACKPAIR(xOffset + prclClip->left,
  1140. xOffset + prclClip->right - 1));
  1141. }
  1142. }
  1143. /******************************Public*Routine******************************\
  1144. * BOOL bFastFill
  1145. *
  1146. * Draws a non-complex, unclipped polygon. 'Non-complex' is defined as
  1147. * having only two edges that are monotonic increasing in 'y'. That is,
  1148. * the polygon cannot have more than one disconnected segment on any given
  1149. * scan. Note that the edges of the polygon can self-intersect, so hourglass
  1150. * shapes are permissible. This restriction permits this routine to run two
  1151. * simultaneous DDAs, and no sorting of the edges is required.
  1152. *
  1153. * Note that NT's fill convention is different from that of Win 3.1 or Win95.
  1154. * With the additional complication of fractional end-points, our convention
  1155. * is the same as in 'X-Windows'. But a DDA is a DDA is a DDA, so once you
  1156. * figure out how we compute the DDA terms for NT, you're golden.
  1157. *
  1158. * This routine handles patterns only when the S3 hardware patterns can be
  1159. * used. The reason for this is that once the S3 pattern initialization is
  1160. * done, pattern fills appear to the programmer exactly the same as solid
  1161. * fills (with the slight difference that different registers and commands
  1162. * are used). Handling 'vM32FillPatSlow' style patterns in this routine
  1163. * would be non-trivial...
  1164. *
  1165. * We take advantage of the fact that the S3 automatically advances the
  1166. * current 'y' to the following scan whenever a rectangle is output so that
  1167. * we have to write to the accelerator three times for every scan: one for
  1168. * the new 'x', one for the new 'width', and one for the drawing command.
  1169. *
  1170. * Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  1171. *
  1172. \**************************************************************************/
  1173. BOOL bFastFill(
  1174. PDEV* ppdev,
  1175. LONG cEdges, // Includes close figure edge
  1176. POINTFIX* pptfxFirst,
  1177. ULONG rop4,
  1178. ULONG iSolidColor,
  1179. RBRUSH* prb,
  1180. POINTL* pptlBrush,
  1181. RECTL* prclClip) // NULL if no clipping
  1182. {
  1183. LONG yTrapezoid; // Top scan for next trapezoid
  1184. LONG cyTrapezoid; // Number of scans in current trapezoid
  1185. LONG yStart; // y-position of start point in current edge
  1186. LONG dM; // Edge delta in FIX units in x direction
  1187. LONG dN; // Edge delta in FIX units in y direction
  1188. LONG i;
  1189. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  1190. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  1191. POINTFIX* pptfxOld; // Start point in current edge
  1192. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  1193. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  1194. // (doesn't include the closefigure edge)
  1195. LONG iEdge;
  1196. LONG lQuotient;
  1197. LONG lRemainder;
  1198. TRAPEZOIDDATA td; // Edge data and stuff
  1199. EDGEDATA* ped; // Points to current edge being processed
  1200. /////////////////////////////////////////////////////////////////
  1201. // See if the polygon is convex
  1202. pptfxScan = pptfxFirst;
  1203. pptfxTop = pptfxFirst; // Assume for now that the first
  1204. // point in path is the topmost
  1205. pptfxLast = pptfxFirst + cEdges - 1;
  1206. if (cEdges <= 2)
  1207. goto ReturnTrue;
  1208. // 'pptfxScan' will always point to the first point in the current
  1209. // edge, and 'cScanEdges' will the number of edges remaining, including
  1210. // the current one:
  1211. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  1212. if ((pptfxScan + 1)->y > pptfxScan->y)
  1213. {
  1214. // Collect all downs:
  1215. do {
  1216. if (--cScanEdges == 0)
  1217. goto SetUpForFilling;
  1218. pptfxScan++;
  1219. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  1220. // Collect all ups:
  1221. do {
  1222. if (--cScanEdges == 0)
  1223. goto SetUpForFillingCheck;
  1224. pptfxScan++;
  1225. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  1226. // Collect all downs:
  1227. pptfxTop = pptfxScan;
  1228. do {
  1229. if ((pptfxScan + 1)->y > pptfxFirst->y)
  1230. break;
  1231. if (--cScanEdges == 0)
  1232. goto SetUpForFilling;
  1233. pptfxScan++;
  1234. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  1235. goto ReturnFalse;
  1236. }
  1237. else
  1238. {
  1239. // Collect all ups:
  1240. do {
  1241. pptfxTop++; // We increment this now because we
  1242. // want it to point to the very last
  1243. // point if we early out in the next
  1244. // statement...
  1245. if (--cScanEdges == 0)
  1246. goto SetUpForFilling;
  1247. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  1248. // Collect all downs:
  1249. pptfxScan = pptfxTop;
  1250. do {
  1251. if (--cScanEdges == 0)
  1252. goto SetUpForFilling;
  1253. pptfxScan++;
  1254. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  1255. // Collect all ups:
  1256. do {
  1257. if ((pptfxScan + 1)->y < pptfxFirst->y)
  1258. break;
  1259. if (--cScanEdges == 0)
  1260. goto SetUpForFilling;
  1261. pptfxScan++;
  1262. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  1263. goto ReturnFalse;
  1264. }
  1265. SetUpForFillingCheck:
  1266. // We check to see if the end of the current edge is higher
  1267. // than the top edge we've found so far:
  1268. if ((pptfxScan + 1)->y < pptfxTop->y)
  1269. pptfxTop = pptfxScan + 1;
  1270. SetUpForFilling:
  1271. /////////////////////////////////////////////////////////////////
  1272. // Some Initialization
  1273. td.aed[LEFT].pptfx = pptfxTop;
  1274. td.aed[RIGHT].pptfx = pptfxTop;
  1275. yTrapezoid = (pptfxTop->y + 15) >> 4;
  1276. // Make sure we initialize the DDAs appropriately:
  1277. td.aed[LEFT].cy = 0;
  1278. td.aed[RIGHT].cy = 0;
  1279. // Guess as to the ordering of the points:
  1280. td.aed[LEFT].dptfx = sizeof(POINTFIX);
  1281. td.aed[RIGHT].dptfx = -(LONG) sizeof(POINTFIX);
  1282. if (ppdev->iMachType == MACH_MM_64)
  1283. {
  1284. vM64TrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  1285. yTrapezoid, prclClip);
  1286. }
  1287. else if (ppdev->iMachType == MACH_MM_32)
  1288. {
  1289. vM32TrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  1290. yTrapezoid, prclClip);
  1291. }
  1292. else
  1293. {
  1294. vI32TrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  1295. yTrapezoid, prclClip);
  1296. }
  1297. NewTrapezoid:
  1298. /////////////////////////////////////////////////////////////////
  1299. // DDA initialization
  1300. for (iEdge = 1; iEdge >= 0; iEdge--)
  1301. {
  1302. ped = &td.aed[iEdge];
  1303. ped->bNew = FALSE;
  1304. if (ped->cy == 0)
  1305. {
  1306. // Our trapezoid drawing routine may want to be notified when
  1307. // it will have to reset its DDA to start a new edge:
  1308. ped->bNew = TRUE;
  1309. // Need a new DDA:
  1310. do {
  1311. cEdges--;
  1312. if (cEdges < 0)
  1313. goto ResetClippingAndReturnTrue;
  1314. // Find the next left edge, accounting for wrapping:
  1315. pptfxOld = ped->pptfx;
  1316. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  1317. if (ped->pptfx < pptfxFirst)
  1318. ped->pptfx = pptfxLast;
  1319. else if (ped->pptfx > pptfxLast)
  1320. ped->pptfx = pptfxFirst;
  1321. // Have to find the edge that spans yTrapezoid:
  1322. ped->cy = ((ped->pptfx->y + 15) >> 4) - yTrapezoid;
  1323. // With fractional coordinate end points, we may get edges
  1324. // that don't cross any scans, in which case we try the
  1325. // next one:
  1326. } while (ped->cy <= 0);
  1327. // 'pptfx' now points to the end point of the edge spanning
  1328. // the scan 'yTrapezoid'.
  1329. dN = ped->pptfx->y - pptfxOld->y;
  1330. dM = ped->pptfx->x - pptfxOld->x;
  1331. ASSERTDD(dN > 0, "Should be going down only");
  1332. // Compute the DDA increment terms:
  1333. ped->dM = dM; // Not used for software trapezoid
  1334. if (dM < 0)
  1335. {
  1336. dM = -dM;
  1337. if (dM < dN) // Can't be '<='
  1338. {
  1339. ped->dx = -1;
  1340. ped->lErrorUp = dN - dM;
  1341. }
  1342. else
  1343. {
  1344. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  1345. ped->dx = -lQuotient; // - dM / dN
  1346. ped->lErrorUp = lRemainder; // dM % dN
  1347. if (ped->lErrorUp > 0)
  1348. {
  1349. ped->dx--;
  1350. ped->lErrorUp = dN - ped->lErrorUp;
  1351. }
  1352. }
  1353. }
  1354. else
  1355. {
  1356. if (dM < dN) // Can't be '<='
  1357. {
  1358. ped->dx = 0;
  1359. ped->lErrorUp = dM;
  1360. }
  1361. else
  1362. {
  1363. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  1364. ped->dx = lQuotient; // dM / dN
  1365. ped->lErrorUp = lRemainder; // dM % dN
  1366. }
  1367. }
  1368. ped->dN = dN; // DDA limit
  1369. ped->lError = -1; // Error is initially zero (add dN - 1 for
  1370. // the ceiling, but subtract off dN so that
  1371. // we can check the sign instead of comparing
  1372. // to dN)
  1373. ped->x = pptfxOld->x;
  1374. yStart = pptfxOld->y;
  1375. if ((yStart & 15) != 0)
  1376. {
  1377. // Advance to the next integer y coordinate
  1378. for (i = 16 - (yStart & 15); i != 0; i--)
  1379. {
  1380. ped->x += ped->dx;
  1381. ped->lError += ped->lErrorUp;
  1382. if (ped->lError >= 0)
  1383. {
  1384. ped->lError -= ped->dN;
  1385. ped->x++;
  1386. }
  1387. }
  1388. }
  1389. if ((ped->x & 15) != 0)
  1390. {
  1391. ped->lError -= ped->dN * (16 - (ped->x & 15));
  1392. ped->x += 15; // We'll want the ceiling in just a bit...
  1393. }
  1394. // Chop off those fractional bits:
  1395. ped->x >>= 4;
  1396. ped->lError >>= 4;
  1397. }
  1398. }
  1399. cyTrapezoid = min(td.aed[LEFT].cy, td.aed[RIGHT].cy); // # of scans in this trap
  1400. td.aed[LEFT].cy -= cyTrapezoid;
  1401. td.aed[RIGHT].cy -= cyTrapezoid;
  1402. td.pfnTrap(&td, yTrapezoid, cyTrapezoid);
  1403. yTrapezoid += cyTrapezoid;
  1404. goto NewTrapezoid;
  1405. ResetClippingAndReturnTrue:
  1406. if (prclClip != NULL)
  1407. {
  1408. vResetClipping(ppdev);
  1409. }
  1410. ReturnTrue:
  1411. if (ppdev->iMachType == MACH_MM_64)
  1412. {
  1413. // Since we don't use a default context, we must restore registers:
  1414. M64_CHECK_FIFO_SPACE(ppdev, ppdev->pjMmBase, 1);
  1415. M64_OD(ppdev->pjMmBase, DST_CNTL, DST_CNTL_XDir | DST_CNTL_YDir);
  1416. }
  1417. return(TRUE);
  1418. ReturnFalse:
  1419. if (ppdev->iMachType == MACH_MM_64)
  1420. {
  1421. // Since we don't use a default context, we must restore registers:
  1422. M64_CHECK_FIFO_SPACE(ppdev, ppdev->pjMmBase, 1);
  1423. M64_OD(ppdev->pjMmBase, DST_CNTL, DST_CNTL_XDir | DST_CNTL_YDir);
  1424. }
  1425. return(FALSE);
  1426. }
  1427.