Source code of Windows XP (NT5)
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.

1311 lines
40 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: fastfill.c
  3. *
  4. * Draws fast convex rectangles.
  5. *
  6. * Copyright (c) 1993-1996 Microsoft Corporation
  7. * Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
  8. \**************************************************************************/
  9. #include "precomp.h"
  10. #define RIGHT 0
  11. #define LEFT 1
  12. typedef struct _TRAPEZOIDDATA TRAPEZOIDDATA; // Handy forward declaration
  13. typedef VOID (FNTRAPEZOID)(TRAPEZOIDDATA*, LONG, LONG);
  14. // Prototype for trapezoid
  15. // drawing routines
  16. typedef struct _EDGEDATA {
  17. LONG x; // Current x position
  18. LONG dx; // # pixels to advance x on each scan
  19. LONG lError; // Current DDA error
  20. LONG lErrorUp; // DDA error increment on each scan
  21. LONG dN; // Signed delta-y in fixed point form (also known
  22. // as the DDA error adjustment, and used to be
  23. // called 'lErrorDown')
  24. LONG dM; // Signed delta-x in fixed point form
  25. POINTFIX* pptfx; // Points to start of current edge
  26. LONG dptfx; // Delta (in bytes) from pptfx to next point
  27. LONG cy; // Number of scans to go for this edge
  28. LONG bNew; // Set to TRUE when a new DDA must be started
  29. // for the edge.
  30. } EDGEDATA; /* ed, ped */
  31. typedef struct _TRAPEZOIDDATA {
  32. FNTRAPEZOID* pfnTrap; // Pointer to appropriate trapezoid drawing routine,
  33. // or trapezoid clip routine
  34. FNTRAPEZOID* pfnTrapClip;// Pointer to appropriate trapezoid drawing routine
  35. // if doing clipping
  36. PDEV* ppdev; // Pointer to PDEV
  37. EDGEDATA aed[2]; // DDA information for both edges
  38. POINTL ptlBrush; // Brush alignment
  39. LONG yClipTop; // Top of clip rectangle
  40. LONG yClipBottom;// Bottom of clip rectangle
  41. // MGA specific stuff below here:
  42. ULONG ulMgaSgn; // Current sign register, MGA specific
  43. ULONG ulLinear; // Linear offset to brush in off-screen memory
  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 vHardwareTrapezoid
  138. *
  139. * Uses the MGA's hardware trapezoid capability to draw solid or two-colour
  140. * pattern trapezoids.
  141. *
  142. \**************************************************************************/
  143. VOID vHardwareTrapezoid(
  144. TRAPEZOIDDATA* ptd,
  145. LONG yTrapezoid,
  146. LONG cyTrapezoid)
  147. {
  148. PDEV* ppdev;
  149. LONG dM;
  150. LONG lError;
  151. BYTE* pjBase;
  152. ppdev = ptd->ppdev;
  153. pjBase = ppdev->pjBase;
  154. if (ptd->aed[LEFT].bNew)
  155. {
  156. dM = ptd->aed[LEFT].dM;
  157. if (dM >= 0)
  158. {
  159. ptd->ulMgaSgn &= ~sdxl_SUB;
  160. lError = -dM - ptd->aed[LEFT].lError - 1;
  161. dM = -dM;
  162. }
  163. else
  164. {
  165. ptd->ulMgaSgn |= sdxl_SUB;
  166. lError = dM + ptd->aed[LEFT].dN + ptd->aed[LEFT].lError;
  167. }
  168. CHECK_FIFO_SPACE(pjBase, 6);
  169. CP_WRITE(pjBase, DWG_AR2, dM);
  170. CP_WRITE(pjBase, DWG_AR1, lError);
  171. CP_WRITE(pjBase, DWG_AR0, ptd->aed[LEFT].dN);
  172. CP_WRITE(pjBase, DWG_FXLEFT, ptd->aed[LEFT].x + ppdev->xOffset);
  173. }
  174. if (ptd->aed[RIGHT].bNew)
  175. {
  176. dM = ptd->aed[RIGHT].dM;
  177. if (dM >= 0)
  178. {
  179. ptd->ulMgaSgn &= ~sdxr_DEC;
  180. lError = -dM - ptd->aed[RIGHT].lError - 1;
  181. dM = -dM;
  182. }
  183. else
  184. {
  185. ptd->ulMgaSgn |= sdxr_DEC;
  186. lError = dM + ptd->aed[RIGHT].dN + ptd->aed[RIGHT].lError;
  187. }
  188. CHECK_FIFO_SPACE(pjBase, 6);
  189. CP_WRITE(pjBase, DWG_AR5, dM);
  190. CP_WRITE(pjBase, DWG_AR4, lError);
  191. CP_WRITE(pjBase, DWG_AR6, ptd->aed[RIGHT].dN);
  192. CP_WRITE(pjBase, DWG_FXRIGHT, ptd->aed[RIGHT].x + ppdev->xOffset);
  193. }
  194. CP_WRITE(pjBase, DWG_SGN, ptd->ulMgaSgn);
  195. CP_START(pjBase, DWG_LEN, cyTrapezoid);
  196. }
  197. /******************************Public*Routine******************************\
  198. * VOID vMilSoftwareTrapezoid
  199. *
  200. * Draws a trapezoid using a software DDA.
  201. *
  202. \**************************************************************************/
  203. VOID vMilSoftwareTrapezoid(
  204. TRAPEZOIDDATA* ptd,
  205. LONG yTrapezoid,
  206. LONG cyTrapezoid)
  207. {
  208. PDEV* ppdev;
  209. LONG xOffset;
  210. LONG xBrush;
  211. ULONG ulOffset;
  212. ULONG ulLinear;
  213. ULONG ulScan;
  214. CHAR cFifo;
  215. LONG lLeftError;
  216. LONG xLeft;
  217. LONG lRightError;
  218. LONG xRight;
  219. ULONG ulAr0Adj;
  220. BYTE* pjBase;
  221. ppdev = ptd->ppdev;
  222. pjBase = ppdev->pjBase;
  223. xBrush = ptd->ptlBrush.x;
  224. ulOffset = ((yTrapezoid - ptd->ptlBrush.y) & 7) << PATTERN_PITCH_SHIFT;
  225. ulLinear = ptd->ulLinear;
  226. // For cjPelSize = 1, 2, 3, or 4,
  227. // ulAr0Adj = 2, 4, 0, or 6.
  228. if (ppdev->cjPelSize == 3)
  229. {
  230. ulAr0Adj = 0;
  231. }
  232. else
  233. {
  234. ulAr0Adj = (ppdev->cjPelSize + 2) & 0xfffffffe;
  235. }
  236. xOffset = ppdev->xOffset;
  237. yTrapezoid += ppdev->yOffset;
  238. // If the left and right edges are vertical, simply output as
  239. // a rectangle.
  240. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  241. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  242. {
  243. xLeft = ptd->aed[LEFT].x + xOffset;
  244. xRight = ptd->aed[RIGHT].x + xOffset - 1; // Inclusive of edge
  245. if (xLeft <= xRight)
  246. {
  247. CHECK_FIFO_SPACE(pjBase, 4);
  248. ulScan = ulLinear + ulOffset + ((xLeft - xBrush) & 7);
  249. CP_WRITE(pjBase, DWG_AR3, ulScan);
  250. if (ulAr0Adj)
  251. {
  252. CP_WRITE(pjBase, DWG_AR0, ((ulScan & 0xfffffff8) |
  253. ((ulScan + ulAr0Adj) & 7)));
  254. }
  255. else
  256. {
  257. CP_WRITE(pjBase, DWG_AR0, (ulScan + 7));
  258. }
  259. CP_WRITE(pjBase, DWG_FXBNDRY,
  260. (xRight << bfxright_SHIFT) |
  261. (xLeft & bfxleft_MASK));
  262. CP_START(pjBase, DWG_YDSTLEN, (yTrapezoid << yval_SHIFT) |
  263. (cyTrapezoid & ylength_MASK));
  264. }
  265. }
  266. else
  267. {
  268. cFifo = 0;
  269. lLeftError = ptd->aed[LEFT].lError;
  270. xLeft = ptd->aed[LEFT].x + xOffset;
  271. lRightError = ptd->aed[RIGHT].lError;
  272. xRight = ptd->aed[RIGHT].x + xOffset - 1; // Inclusive of edge
  273. while (TRUE)
  274. {
  275. /////////////////////////////////////////////////////////////////
  276. // Run the DDAs
  277. if (xLeft <= xRight)
  278. {
  279. // We get a little tricky here and try to amortize the cost of
  280. // the read for checking the FIFO count on the MGA. Doing
  281. // so got us a 25% win on large triangles on a P90.
  282. cFifo -= 4;
  283. if (cFifo < 0)
  284. {
  285. do
  286. {
  287. cFifo = GET_FIFO_SPACE(pjBase) - 4;
  288. } while (cFifo < 0);
  289. }
  290. ulScan = ulLinear + ulOffset + ((xLeft - xBrush) & 7);
  291. CP_WRITE(pjBase, DWG_AR3, ulScan);
  292. if (ulAr0Adj)
  293. {
  294. CP_WRITE(pjBase, DWG_AR0, ((ulScan & 0xfffffff8) |
  295. ((ulScan + ulAr0Adj) & 7)));
  296. }
  297. else
  298. {
  299. CP_WRITE(pjBase, DWG_AR0, (ulScan + 7));
  300. }
  301. CP_WRITE(pjBase, DWG_FXBNDRY, (xRight << bfxright_SHIFT) |
  302. (xLeft & bfxleft_MASK));
  303. CP_START(pjBase, DWG_YDSTLEN, (yTrapezoid << yval_SHIFT) |
  304. (1 & ylength_MASK));
  305. }
  306. ulOffset = (ulOffset + (1 << PATTERN_PITCH_SHIFT)) &
  307. (7 << PATTERN_PITCH_SHIFT);
  308. yTrapezoid++;
  309. // Advance the right wall.
  310. xRight += ptd->aed[RIGHT].dx;
  311. lRightError += ptd->aed[RIGHT].lErrorUp;
  312. if (lRightError >= 0)
  313. {
  314. lRightError -= ptd->aed[RIGHT].dN;
  315. xRight++;
  316. }
  317. // Advance the left wall.
  318. xLeft += ptd->aed[LEFT].dx;
  319. lLeftError += ptd->aed[LEFT].lErrorUp;
  320. if (lLeftError >= 0)
  321. {
  322. lLeftError -= ptd->aed[LEFT].dN;
  323. xLeft++;
  324. }
  325. cyTrapezoid--;
  326. if (cyTrapezoid == 0)
  327. break;
  328. }
  329. ptd->aed[LEFT].lError = lLeftError;
  330. ptd->aed[LEFT].x = xLeft - xOffset;
  331. ptd->aed[RIGHT].lError = lRightError;
  332. ptd->aed[RIGHT].x = xRight - xOffset + 1;
  333. }
  334. }
  335. /******************************Public*Routine******************************\
  336. * VOID vMilTrapezoidSetup
  337. *
  338. * Initialize the hardware and some state for doing trapezoids.
  339. *
  340. \**************************************************************************/
  341. VOID vMilTrapezoidSetup(
  342. PDEV* ppdev,
  343. ULONG rop4,
  344. ULONG iSolidColor,
  345. RBRUSH* prb,
  346. POINTL* pptlBrush,
  347. TRAPEZOIDDATA* ptd,
  348. LONG yStart, // First scan for drawing
  349. RECTL* prclClip) // NULL if no clipping
  350. {
  351. ULONG ulHwMix;
  352. ULONG ulDwg;
  353. LONG xOffset;
  354. LONG yOffset;
  355. BRUSHENTRY* pbe;
  356. BYTE* pjBase;
  357. pjBase = ppdev->pjBase;
  358. ptd->ppdev = ppdev;
  359. ptd->ulMgaSgn = 0;
  360. xOffset = ppdev->xOffset;
  361. yOffset = ppdev->yOffset;
  362. if ((prclClip != NULL) && (prclClip->top > yStart))
  363. yStart = prclClip->top;
  364. if (iSolidColor != -1)
  365. {
  366. // Solid fill.
  367. ptd->pfnTrap = vHardwareTrapezoid;
  368. CHECK_FIFO_SPACE(pjBase, 3);
  369. if (rop4 == 0xf0f0)
  370. {
  371. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_TRAP + atype_RPL +
  372. solid_SOLID + bop_SRCCOPY +
  373. transc_BG_OPAQUE));
  374. }
  375. else
  376. {
  377. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  378. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_TRAP + atype_RSTR +
  379. solid_SOLID + (ulHwMix << 16) +
  380. transc_BG_OPAQUE));
  381. }
  382. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, iSolidColor));
  383. CP_WRITE(pjBase, DWG_YDST, yStart + yOffset);
  384. ppdev->HopeFlags = PATTERN_CACHE;
  385. }
  386. else
  387. {
  388. // Pattern fill.
  389. if (prb->fl & RBRUSH_2COLOR)
  390. {
  391. // Monochrome brush.
  392. ptd->pfnTrap = vHardwareTrapezoid;
  393. if ((rop4 & 0xff) == 0xf0)
  394. {
  395. ulDwg = opcode_TRAP + atype_RPL + bop_SRCCOPY;
  396. }
  397. else
  398. {
  399. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  400. ulDwg = opcode_TRAP + atype_RSTR + (ulHwMix << 16);
  401. }
  402. if (((rop4 >> 8) & 0xff) == (rop4 & 0xff))
  403. {
  404. // Normal opaque mode.
  405. ulDwg |= transc_BG_OPAQUE;
  406. }
  407. else
  408. {
  409. // GDI guarantees us that if the foreground and background
  410. // ROPs are different, the background rop is LEAVEALONE.
  411. ulDwg |= transc_BG_TRANSP;
  412. }
  413. CHECK_FIFO_SPACE(pjBase, 9);
  414. CP_WRITE(pjBase, DWG_DWGCTL, ulDwg);
  415. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, prb->ulColor[1]));
  416. CP_WRITE(pjBase, DWG_BCOL, COLOR_REPLICATE(ppdev, prb->ulColor[0]));
  417. CP_WRITE(pjBase, DWG_SRC0, prb->aulPattern[0]);
  418. CP_WRITE(pjBase, DWG_SRC1, prb->aulPattern[1]);
  419. CP_WRITE(pjBase, DWG_SRC2, prb->aulPattern[2]);
  420. CP_WRITE(pjBase, DWG_SRC3, prb->aulPattern[3]);
  421. CP_WRITE(pjBase, DWG_YDST, yStart + yOffset);
  422. CP_WRITE(pjBase, DWG_SHIFT,
  423. ((-(pptlBrush->y + ppdev->yOffset) & 7) << 4) |
  424. (-(pptlBrush->x + ppdev->xOffset) & 7));
  425. }
  426. else
  427. {
  428. // Color brush.
  429. // We have to ensure that no other brush took our spot in
  430. // off-screen memory.
  431. pbe = prb->apbe[IBOARD(ppdev)];
  432. if (pbe->prbVerify != prb)
  433. {
  434. // Download the brush into the cache.
  435. if (ppdev->cjPelSize != 3)
  436. {
  437. vMilPatRealize(ppdev, prb);
  438. }
  439. else
  440. {
  441. vMilPatRealize24bpp(ppdev, prb);
  442. }
  443. pbe = prb->apbe[IBOARD(ppdev)];
  444. }
  445. ptd->pfnTrap = vMilSoftwareTrapezoid;
  446. ptd->ulLinear = pbe->ulLinear;
  447. ptd->ptlBrush = *pptlBrush;
  448. CHECK_FIFO_SPACE(pjBase, 2);
  449. if (rop4 == 0xf0f0) // PATCOPY
  450. {
  451. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RPL +
  452. sgnzero_ZERO + shftzero_ZERO +
  453. bop_SRCCOPY + bltmod_BFCOL +
  454. pattern_ON + transc_BG_OPAQUE));
  455. }
  456. else
  457. {
  458. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  459. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RSTR +
  460. sgnzero_ZERO + shftzero_ZERO +
  461. (ulHwMix << 16) +
  462. bltmod_BFCOL + pattern_ON +
  463. transc_BG_OPAQUE));
  464. }
  465. CP_WRITE(pjBase, DWG_AR5, PATTERN_PITCH);
  466. }
  467. ppdev->HopeFlags = 0;
  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. CHECK_FIFO_SPACE(pjBase, 2);
  476. CP_WRITE(pjBase, DWG_CXLEFT, prclClip->left + xOffset);
  477. CP_WRITE(pjBase, DWG_CXRIGHT, prclClip->right + xOffset - 1);
  478. }
  479. }
  480. /******************************Public*Routine******************************\
  481. * VOID vMgaSoftwareTrapezoid
  482. *
  483. * Draws a trapezoid using a software DDA.
  484. *
  485. \**************************************************************************/
  486. VOID vMgaSoftwareTrapezoid(
  487. TRAPEZOIDDATA* ptd,
  488. LONG yTrapezoid,
  489. LONG cyTrapezoid)
  490. {
  491. PDEV* ppdev;
  492. BYTE* pjBase;
  493. LONG xOffset;
  494. LONG xBrush;
  495. ULONG ulOffset;
  496. ULONG ulLinear;
  497. ULONG ulScan;
  498. CHAR cFifo;
  499. LONG lLeftError;
  500. LONG xLeft;
  501. LONG lRightError;
  502. LONG xRight;
  503. ppdev = ptd->ppdev;
  504. pjBase = ppdev->pjBase;
  505. xBrush = ptd->ptlBrush.x;
  506. ulOffset = ((yTrapezoid - ptd->ptlBrush.y) & 7) << 5;
  507. ulLinear = ptd->ulLinear;
  508. xOffset = ppdev->xOffset;
  509. yTrapezoid += ppdev->yOffset;
  510. // If the left and right edges are vertical, simply output as
  511. // a rectangle:
  512. if (((ptd->aed[LEFT].lErrorUp | ptd->aed[RIGHT].lErrorUp) == 0) &&
  513. ((ptd->aed[LEFT].dx | ptd->aed[RIGHT].dx) == 0))
  514. {
  515. xLeft = ptd->aed[LEFT].x + xOffset;
  516. xRight = ptd->aed[RIGHT].x + xOffset - 1; // Inclusive of edge
  517. if (xLeft <= xRight)
  518. {
  519. CHECK_FIFO_SPACE(pjBase, 6);
  520. CP_WRITE(pjBase, DWG_FXLEFT, xLeft); // xOffset already added in
  521. CP_WRITE(pjBase, DWG_FXRIGHT, xRight);
  522. ulScan = ulLinear + ulOffset;
  523. CP_WRITE(pjBase, DWG_AR3, ulScan + ((xLeft - xBrush) & 7));
  524. CP_WRITE(pjBase, DWG_AR0, ulScan + 15);
  525. CP_WRITE(pjBase, DWG_LEN, cyTrapezoid);
  526. CP_START(pjBase, DWG_YDST, yTrapezoid);
  527. }
  528. }
  529. else
  530. {
  531. cFifo = 0;
  532. lLeftError = ptd->aed[LEFT].lError;
  533. xLeft = ptd->aed[LEFT].x + xOffset;
  534. lRightError = ptd->aed[RIGHT].lError;
  535. xRight = ptd->aed[RIGHT].x + xOffset - 1; // Inclusive of edge
  536. while (TRUE)
  537. {
  538. /////////////////////////////////////////////////////////////////
  539. // Run the DDAs
  540. if (xLeft <= xRight)
  541. {
  542. // We get a little tricky here and try to amortize the cost of
  543. // the read for checking the FIFO count on the MGA. Doing
  544. // so got us a 25% win on large triangles on a P90:
  545. cFifo -= 6;
  546. if (cFifo < 0)
  547. {
  548. do {
  549. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  550. } while (cFifo < 0);
  551. }
  552. CP_WRITE(pjBase, DWG_FXLEFT, xLeft);
  553. CP_WRITE(pjBase, DWG_FXRIGHT, xRight);
  554. ulScan = ulLinear + ulOffset;
  555. CP_WRITE(pjBase, DWG_AR0, ulScan + 15);
  556. CP_WRITE(pjBase, DWG_AR3, ulScan + ((xLeft - xBrush) & 7));
  557. CP_WRITE(pjBase, DWG_LEN, 1);
  558. CP_START(pjBase, DWG_YDST, yTrapezoid);
  559. }
  560. ulOffset = (ulOffset + (1 << 5)) & (7 << 5);
  561. yTrapezoid++;
  562. // Advance the right wall:
  563. xRight += ptd->aed[RIGHT].dx;
  564. lRightError += ptd->aed[RIGHT].lErrorUp;
  565. if (lRightError >= 0)
  566. {
  567. lRightError -= ptd->aed[RIGHT].dN;
  568. xRight++;
  569. }
  570. // Advance the left wall:
  571. xLeft += ptd->aed[LEFT].dx;
  572. lLeftError += ptd->aed[LEFT].lErrorUp;
  573. if (lLeftError >= 0)
  574. {
  575. lLeftError -= ptd->aed[LEFT].dN;
  576. xLeft++;
  577. }
  578. cyTrapezoid--;
  579. if (cyTrapezoid == 0)
  580. break;
  581. }
  582. ptd->aed[LEFT].lError = lLeftError;
  583. ptd->aed[LEFT].x = xLeft - xOffset;
  584. ptd->aed[RIGHT].lError = lRightError;
  585. ptd->aed[RIGHT].x = xRight - xOffset + 1;
  586. }
  587. }
  588. /******************************Public*Routine******************************\
  589. * VOID vMgaTrapezoidSetup
  590. *
  591. * Initialize the hardware and some state for doing trapezoids.
  592. *
  593. \**************************************************************************/
  594. VOID vMgaTrapezoidSetup(
  595. PDEV* ppdev,
  596. ULONG rop4,
  597. ULONG iSolidColor,
  598. RBRUSH* prb,
  599. POINTL* pptlBrush,
  600. TRAPEZOIDDATA* ptd,
  601. LONG yStart, // First scan for drawing
  602. RECTL* prclClip) // NULL if no clipping
  603. {
  604. BYTE* pjBase;
  605. ULONG ulHwMix;
  606. ULONG ulDwg;
  607. BRUSHENTRY* pbe;
  608. ptd->ppdev = ppdev;
  609. ptd->ulMgaSgn = 0;
  610. pjBase = ppdev->pjBase;
  611. if ((prclClip != NULL) && (prclClip->top > yStart))
  612. yStart = prclClip->top;
  613. if (iSolidColor != -1)
  614. {
  615. ptd->pfnTrap = vHardwareTrapezoid;
  616. CHECK_FIFO_SPACE(pjBase, 7);
  617. if (rop4 == 0xf0f0)
  618. {
  619. CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + transc_BG_OPAQUE +
  620. blockm_ON + atype_RPL + bop_SRCCOPY);
  621. }
  622. else
  623. {
  624. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  625. CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + transc_BG_OPAQUE +
  626. blockm_OFF + atype_RSTR +
  627. (ulHwMix << 16));
  628. }
  629. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, iSolidColor));
  630. CP_WRITE(pjBase, DWG_YDST, yStart + ppdev->yOffset);
  631. if (!(GET_CACHE_FLAGS(ppdev, PATTERN_CACHE)))
  632. {
  633. CP_WRITE(pjBase, DWG_SRC0, 0xFFFFFFFF);
  634. CP_WRITE(pjBase, DWG_SRC1, 0xFFFFFFFF);
  635. CP_WRITE(pjBase, DWG_SRC2, 0xFFFFFFFF);
  636. CP_WRITE(pjBase, DWG_SRC3, 0xFFFFFFFF);
  637. }
  638. ppdev->HopeFlags = PATTERN_CACHE;
  639. }
  640. else
  641. {
  642. if (prb->fl & RBRUSH_2COLOR)
  643. {
  644. ptd->pfnTrap = vHardwareTrapezoid;
  645. if ((rop4 & 0xff) == 0xf0)
  646. {
  647. ulDwg = opcode_TRAP + blockm_OFF + atype_RPL + bop_SRCCOPY;
  648. }
  649. else
  650. {
  651. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  652. ulDwg = opcode_TRAP + blockm_OFF + atype_RSTR + (ulHwMix << 16);
  653. }
  654. if (((rop4 >> 8) & 0xff) == (rop4 & 0xff))
  655. {
  656. // Normal opaque mode:
  657. ulDwg |= transc_BG_OPAQUE;
  658. }
  659. else
  660. {
  661. // GDI guarantees us that if the foreground and background
  662. // ROPs are different, the background rop is LEAVEALONE:
  663. ulDwg |= transc_BG_TRANSP;
  664. }
  665. CHECK_FIFO_SPACE(pjBase, 9);
  666. CP_WRITE(pjBase, DWG_DWGCTL, ulDwg);
  667. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, prb->ulColor[1]));
  668. CP_WRITE(pjBase, DWG_BCOL, COLOR_REPLICATE(ppdev, prb->ulColor[0]));
  669. CP_WRITE(pjBase, DWG_SRC0, prb->aulPattern[0]);
  670. CP_WRITE(pjBase, DWG_SRC1, prb->aulPattern[1]);
  671. CP_WRITE(pjBase, DWG_SRC2, prb->aulPattern[2]);
  672. CP_WRITE(pjBase, DWG_SRC3, prb->aulPattern[3]);
  673. CP_WRITE(pjBase, DWG_YDST, yStart + ppdev->yOffset);
  674. CP_WRITE(pjBase, DWG_SHIFT,
  675. ((-(pptlBrush->y + ppdev->yOffset) & 7) << 4) |
  676. (-(pptlBrush->x + ppdev->xOffset) & 7));
  677. ppdev->HopeFlags = 0;
  678. }
  679. else
  680. {
  681. // We have to ensure that no other brush took our spot in off-screen
  682. // memory:
  683. ASSERTDD(ppdev->iBitmapFormat == BMF_8BPP,
  684. "Can only do 8bpp patterned fastfills");
  685. if (prb->apbe[IBOARD(ppdev)]->prbVerify != prb)
  686. {
  687. vMgaPatRealize8bpp(ppdev, prb);
  688. }
  689. pjBase = ppdev->pjBase;
  690. pbe = prb->apbe[IBOARD(ppdev)];
  691. ptd->pfnTrap = vMgaSoftwareTrapezoid;
  692. ptd->ulLinear = pbe->ulLinear;
  693. ptd->ptlBrush = *pptlBrush;
  694. CHECK_FIFO_SPACE(pjBase, 4);
  695. if (rop4 == 0xf0f0) // PATCOPY
  696. {
  697. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RPL + blockm_OFF +
  698. trans_0 + bltmod_BFCOL + pattern_ON +
  699. transc_BG_OPAQUE + bop_SRCCOPY));
  700. }
  701. else
  702. {
  703. RIP("Shouldn't allow ROPs for now, because of h/w bug!");
  704. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  705. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RSTR + blockm_OFF +
  706. trans_0 + bltmod_BFCOL + pattern_ON +
  707. transc_BG_OPAQUE + (ulHwMix << 16)));
  708. }
  709. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  710. {
  711. CP_WRITE(pjBase, DWG_SGN, 0);
  712. }
  713. ppdev->HopeFlags = SIGN_CACHE;
  714. CP_WRITE(pjBase, DWG_SHIFT, 0);
  715. CP_WRITE(pjBase, DWG_AR5, 32);
  716. }
  717. }
  718. if (prclClip != NULL)
  719. {
  720. ptd->pfnTrapClip = ptd->pfnTrap;
  721. ptd->pfnTrap = vClipTrapezoid;
  722. ptd->yClipTop = prclClip->top;
  723. ptd->yClipBottom = prclClip->bottom;
  724. CHECK_FIFO_SPACE(pjBase, 2);
  725. CP_WRITE(pjBase, DWG_CXLEFT, ppdev->xOffset + prclClip->left);
  726. CP_WRITE(pjBase, DWG_CXRIGHT, ppdev->xOffset + prclClip->right - 1);
  727. }
  728. }
  729. /******************************Public*Routine******************************\
  730. * BOOL bFastFill
  731. *
  732. * Draws a non-complex, unclipped polygon. 'Non-complex' is defined as
  733. * having only two edges that are monotonic increasing in 'y'. That is,
  734. * the polygon cannot have more than one disconnected segment on any given
  735. * scan. Note that the edges of the polygon can self-intersect, so hourglass
  736. * shapes are permissible. This restriction permits this routine to run two
  737. * simultaneous DDAs, and no sorting of the edges is required.
  738. *
  739. * Note that NT's fill convention is different from that of Win 3.1 or Win95.
  740. * With the additional complication of fractional end-points, our convention
  741. * is the same as in 'X-Windows'. But a DDA is a DDA is a DDA, so once you
  742. * figure out how we compute the DDA terms for NT, you're golden.
  743. *
  744. * Returns TRUE if the polygon was drawn; FALSE if the polygon was complex.
  745. *
  746. \**************************************************************************/
  747. BOOL bFastFill(
  748. PDEV* ppdev,
  749. LONG cEdges, // Includes close figure edge
  750. POINTFIX* pptfxFirst,
  751. ULONG rop4,
  752. ULONG iSolidColor,
  753. RBRUSH* prb,
  754. POINTL* pptlBrush,
  755. RECTL* prclClip) // NULL if no clipping
  756. {
  757. LONG yTrapezoid; // Top scan for next trapezoid
  758. LONG cyTrapezoid; // Number of scans in current trapezoid
  759. LONG yStart; // y-position of start point in current edge
  760. LONG dM; // Edge delta in FIX units in x direction
  761. LONG dN; // Edge delta in FIX units in y direction
  762. LONG i;
  763. LONG lCross; // Cross-product result
  764. POINTFIX* pptfxLast; // Points to the last point in the polygon array
  765. POINTFIX* pptfxTop; // Points to the top-most point in the polygon
  766. POINTFIX* pptfxOld; // Start point in current edge
  767. POINTFIX* pptfxScan; // Current edge pointer for finding pptfxTop
  768. LONG cScanEdges; // Number of edges scanned to find pptfxTop
  769. // (doesn't include the closefigure edge)
  770. LONG iEdge;
  771. LONG lQuotient;
  772. LONG lRemainder;
  773. BYTE* pjBase;
  774. TRAPEZOIDDATA td; // Edge data and stuff
  775. EDGEDATA* ped; // Points to current edge being processed
  776. /////////////////////////////////////////////////////////////////
  777. // See if the polygon is convex
  778. pptfxScan = pptfxFirst;
  779. pptfxTop = pptfxFirst; // Assume for now that the first
  780. // point in path is the topmost
  781. pptfxLast = pptfxFirst + cEdges - 1;
  782. // Watch for close figure points, because we have the later restriction
  783. // that we won't allow coincident vertices:
  784. if ((pptfxLast->x == pptfxFirst->x) && (pptfxLast->y == pptfxFirst->y))
  785. {
  786. pptfxLast--;
  787. cEdges--;
  788. }
  789. if (cEdges <= 2)
  790. goto ReturnTrue;
  791. // 'pptfxScan' will always point to the first point in the current
  792. // edge, and 'cScanEdges' will the number of edges remaining, including
  793. // the current one:
  794. cScanEdges = cEdges - 1; // The number of edges, not counting close figure
  795. if ((pptfxScan + 1)->y > pptfxScan->y)
  796. {
  797. // Collect all downs:
  798. do {
  799. if (--cScanEdges == 0)
  800. goto SetUpForFilling;
  801. pptfxScan++;
  802. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  803. // Collect all ups:
  804. do {
  805. if (--cScanEdges == 0)
  806. goto SetUpForFillingCheck;
  807. pptfxScan++;
  808. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  809. // Collect all downs:
  810. pptfxTop = pptfxScan;
  811. do {
  812. if ((pptfxScan + 1)->y > pptfxFirst->y)
  813. break;
  814. if (--cScanEdges == 0)
  815. goto SetUpForFilling;
  816. pptfxScan++;
  817. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  818. goto ReturnFalse;
  819. }
  820. else
  821. {
  822. // Collect all ups:
  823. do {
  824. pptfxTop++; // We increment this now because we
  825. // want it to point to the very last
  826. // point if we early out in the next
  827. // statement...
  828. if (--cScanEdges == 0)
  829. goto SetUpForFilling;
  830. } while ((pptfxTop + 1)->y <= pptfxTop->y);
  831. // Collect all downs:
  832. pptfxScan = pptfxTop;
  833. do {
  834. if (--cScanEdges == 0)
  835. goto SetUpForFilling;
  836. pptfxScan++;
  837. } while ((pptfxScan + 1)->y >= pptfxScan->y);
  838. // Collect all ups:
  839. do {
  840. if ((pptfxScan + 1)->y < pptfxFirst->y)
  841. break;
  842. if (--cScanEdges == 0)
  843. goto SetUpForFilling;
  844. pptfxScan++;
  845. } while ((pptfxScan + 1)->y <= pptfxScan->y);
  846. goto ReturnFalse;
  847. }
  848. SetUpForFillingCheck:
  849. // We check to see if the end of the current edge is higher
  850. // than the top edge we've found so far:
  851. if ((pptfxScan + 1)->y < pptfxTop->y)
  852. pptfxTop = pptfxScan + 1;
  853. SetUpForFilling:
  854. pptfxScan = pptfxFirst;
  855. cScanEdges = cEdges - 2;
  856. // NOTE: For a bit of speed and simplicity, we will assume that
  857. // our cross product calculations will not overflow. A
  858. // consequence of this is that the caller MUST ensure that
  859. // the bounds of the polygon are small enough that there
  860. // will be no overflow.
  861. lCross = (((pptfxScan + 1)->x - (pptfxScan + 0)->x)
  862. * ((pptfxScan + 2)->y - (pptfxScan + 1)->y)
  863. - ((pptfxScan + 1)->y - (pptfxScan + 0)->y)
  864. * ((pptfxScan + 2)->x - (pptfxScan + 1)->x));
  865. if (lCross == 0)
  866. {
  867. // We don't allow any colinear points into FastFill. We do this
  868. // here because we would need a non-zero cross product to determine
  869. // which direction the rest of the edges should go. We do this
  870. // later so that coincident vertices will never mess us up by
  871. // hiding a cross product sign change.
  872. goto ReturnFalse;
  873. }
  874. else if (lCross > 0)
  875. {
  876. // Make sure all cross products are positive:
  877. pptfxScan++;
  878. while (--cScanEdges != 0)
  879. {
  880. if (((pptfxScan + 1)->x - (pptfxScan + 0)->x)
  881. * ((pptfxScan + 2)->y - (pptfxScan + 1)->y)
  882. - ((pptfxScan + 1)->y - (pptfxScan + 0)->y)
  883. * ((pptfxScan + 2)->x - (pptfxScan + 1)->x) <= 0)
  884. {
  885. goto ReturnFalse;
  886. }
  887. pptfxScan++;
  888. }
  889. // Check the angles formed by the closefigure edge:
  890. if (((pptfxScan + 1)->x - (pptfxScan + 0)->x)
  891. * ((pptfxFirst )->y - (pptfxScan + 1)->y)
  892. - ((pptfxScan + 1)->y - (pptfxScan + 0)->y)
  893. * ((pptfxFirst )->x - (pptfxScan + 1)->x) <= 0)
  894. {
  895. goto ReturnFalse;
  896. }
  897. if (((pptfxFirst )->x - (pptfxScan + 1)->x)
  898. * ((pptfxFirst + 1)->y - (pptfxFirst )->y)
  899. - ((pptfxFirst )->y - (pptfxScan + 1)->y)
  900. * ((pptfxFirst + 1)->x - (pptfxFirst )->x) <= 0)
  901. {
  902. goto ReturnFalse;
  903. }
  904. // The figure has its points ordered in a clockwise direction:
  905. td.aed[LEFT].dptfx = -(LONG) sizeof(POINTFIX);
  906. td.aed[RIGHT].dptfx = sizeof(POINTFIX);
  907. }
  908. else
  909. {
  910. // Make sure all cross products are negative:
  911. pptfxScan++;
  912. while (--cScanEdges != 0)
  913. {
  914. if (((pptfxScan + 1)->x - (pptfxScan + 0)->x)
  915. * ((pptfxScan + 2)->y - (pptfxScan + 1)->y)
  916. - ((pptfxScan + 1)->y - (pptfxScan + 0)->y)
  917. * ((pptfxScan + 2)->x - (pptfxScan + 1)->x) >= 0)
  918. {
  919. goto ReturnFalse;
  920. }
  921. pptfxScan++;
  922. }
  923. // Check the angles formed by the closefigure edge:
  924. if (((pptfxScan + 1)->x - (pptfxScan + 0)->x)
  925. * ((pptfxFirst )->y - (pptfxScan + 1)->y)
  926. - ((pptfxScan + 1)->y - (pptfxScan + 0)->y)
  927. * ((pptfxFirst )->x - (pptfxScan + 1)->x) >= 0)
  928. {
  929. goto ReturnFalse;
  930. }
  931. if (((pptfxFirst )->x - (pptfxScan + 1)->x)
  932. * ((pptfxFirst + 1)->y - (pptfxFirst )->y)
  933. - ((pptfxFirst )->y - (pptfxScan + 1)->y)
  934. * ((pptfxFirst + 1)->x - (pptfxFirst )->x) >= 0)
  935. {
  936. goto ReturnFalse;
  937. }
  938. // The figure has its points ordered in a counter-clockwise direction:
  939. td.aed[LEFT].dptfx = sizeof(POINTFIX);
  940. td.aed[RIGHT].dptfx = -(LONG) sizeof(POINTFIX);
  941. }
  942. /////////////////////////////////////////////////////////////////
  943. // Some Initialization
  944. td.aed[LEFT].pptfx = pptfxTop;
  945. td.aed[RIGHT].pptfx = pptfxTop;
  946. yTrapezoid = (pptfxTop->y + 15) >> 4;
  947. // Make sure we initialize the DDAs appropriately:
  948. td.aed[LEFT].cy = 0;
  949. td.aed[RIGHT].cy = 0;
  950. if (ppdev->ulBoardId == MGA_STORM)
  951. {
  952. vMilTrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  953. yTrapezoid, prclClip);
  954. }
  955. else
  956. {
  957. vMgaTrapezoidSetup(ppdev, rop4, iSolidColor, prb, pptlBrush, &td,
  958. yTrapezoid, prclClip);
  959. }
  960. NewTrapezoid:
  961. /////////////////////////////////////////////////////////////////
  962. // DDA initialization
  963. for (iEdge = 1; iEdge >= 0; iEdge--)
  964. {
  965. ped = &td.aed[iEdge];
  966. ped->bNew = FALSE;
  967. if (ped->cy == 0)
  968. {
  969. // Our trapezoid drawing routine may want to be notified when
  970. // it will have to reset its DDA to start a new edge:
  971. ped->bNew = TRUE;
  972. // Need a new DDA:
  973. do {
  974. cEdges--;
  975. if (cEdges < 0)
  976. goto ResetClippingAndReturnTrue;
  977. // Find the next left edge, accounting for wrapping:
  978. pptfxOld = ped->pptfx;
  979. ped->pptfx = (POINTFIX*) ((BYTE*) ped->pptfx + ped->dptfx);
  980. if (ped->pptfx < pptfxFirst)
  981. ped->pptfx = pptfxLast;
  982. else if (ped->pptfx > pptfxLast)
  983. ped->pptfx = pptfxFirst;
  984. // Have to find the edge that spans yTrapezoid:
  985. ped->cy = ((ped->pptfx->y + 15) >> 4) - yTrapezoid;
  986. // With fractional coordinate end points, we may get edges
  987. // that don't cross any scans, in which case we try the
  988. // next one:
  989. } while (ped->cy <= 0);
  990. // 'pptfx' now points to the end point of the edge spanning
  991. // the scan 'yTrapezoid'.
  992. dN = ped->pptfx->y - pptfxOld->y;
  993. dM = ped->pptfx->x - pptfxOld->x;
  994. ASSERTDD(dN > 0, "Should be going down only");
  995. // Compute the DDA increment terms:
  996. ped->dM = dM; // Not used for software trapezoid
  997. if (dM < 0)
  998. {
  999. dM = -dM;
  1000. if (dM < dN) // Can't be '<='
  1001. {
  1002. ped->dx = -1;
  1003. ped->lErrorUp = dN - dM;
  1004. }
  1005. else
  1006. {
  1007. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  1008. ped->dx = -lQuotient; // - dM / dN
  1009. ped->lErrorUp = lRemainder; // dM % dN
  1010. if (ped->lErrorUp > 0)
  1011. {
  1012. ped->dx--;
  1013. ped->lErrorUp = dN - ped->lErrorUp;
  1014. }
  1015. }
  1016. }
  1017. else
  1018. {
  1019. if (dM < dN) // Can't be '<='
  1020. {
  1021. ped->dx = 0;
  1022. ped->lErrorUp = dM;
  1023. }
  1024. else
  1025. {
  1026. QUOTIENT_REMAINDER(dM, dN, lQuotient, lRemainder);
  1027. ped->dx = lQuotient; // dM / dN
  1028. ped->lErrorUp = lRemainder; // dM % dN
  1029. }
  1030. }
  1031. ped->dN = dN; // DDA limit
  1032. ped->lError = -1; // Error is initially zero (add dN - 1 for
  1033. // the ceiling, but subtract off dN so that
  1034. // we can check the sign instead of comparing
  1035. // to dN)
  1036. ped->x = pptfxOld->x;
  1037. yStart = pptfxOld->y;
  1038. if ((yStart & 15) != 0)
  1039. {
  1040. // Advance to the next integer y coordinate
  1041. for (i = 16 - (yStart & 15); i != 0; i--)
  1042. {
  1043. ped->x += ped->dx;
  1044. ped->lError += ped->lErrorUp;
  1045. if (ped->lError >= 0)
  1046. {
  1047. ped->lError -= ped->dN;
  1048. ped->x++;
  1049. }
  1050. }
  1051. }
  1052. if ((ped->x & 15) != 0)
  1053. {
  1054. ped->lError -= ped->dN * (16 - (ped->x & 15));
  1055. ped->x += 15; // We'll want the ceiling in just a bit...
  1056. }
  1057. // Chop off those fractional bits:
  1058. ped->x >>= 4;
  1059. ped->lError >>= 4;
  1060. }
  1061. }
  1062. cyTrapezoid = min(td.aed[LEFT].cy, td.aed[RIGHT].cy); // # of scans in this trap
  1063. td.aed[LEFT].cy -= cyTrapezoid;
  1064. td.aed[RIGHT].cy -= cyTrapezoid;
  1065. td.pfnTrap(&td, yTrapezoid, cyTrapezoid);
  1066. yTrapezoid += cyTrapezoid;
  1067. goto NewTrapezoid;
  1068. ResetClippingAndReturnTrue:
  1069. if (prclClip != NULL)
  1070. {
  1071. pjBase = ppdev->pjBase;
  1072. CHECK_FIFO_SPACE(pjBase, 2);
  1073. CP_WRITE(pjBase, DWG_CXLEFT, 0);
  1074. CP_WRITE(pjBase, DWG_CXRIGHT, ppdev->cxMemory - 1);
  1075. }
  1076. ReturnTrue:
  1077. return(TRUE);
  1078. ReturnFalse:
  1079. return(FALSE);
  1080. }