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.

1074 lines
34 KiB

  1. /******************************************************************************\
  2. *
  3. * $Workfile: brush.c $
  4. *
  5. * Handles all brush/pattern initialization and realization.
  6. *
  7. * Copyright (c) 1992-1995 Microsoft Corporation
  8. * Copyright (c) 1996 Cirrus Logic, Inc.
  9. *
  10. * $Log: S:/projects/drivers/ntsrc/display/brush.c_v $
  11. *
  12. * Rev 1.3 Nov 26 1996 14:28:48 unknown
  13. * Use second aperture for blt.
  14. *
  15. * Rev 1.2 Nov 07 1996 16:44:50 unknown
  16. * Clean up CAPS flags
  17. *
  18. * Rev 1.1 Oct 10 1996 15:36:16 unknown
  19. *
  20. *
  21. * Rev 1.5 13 Aug 1996 11:55:34 frido
  22. * Fixed misalignment in brush cache.
  23. *
  24. * Rev 1.4 12 Aug 1996 17:08:08 frido
  25. * Commented brush cache.
  26. * Removed unaccessed local variables.
  27. *
  28. * Rev 1.3 05 Aug 1996 11:17:50 frido
  29. * Added more check for XLATEOBJ.
  30. *
  31. * Rev 1.2 31 Jul 1996 15:43:28 frido
  32. * Added new brush caches.
  33. *
  34. * jl01 10-08-96 Do Transparent BLT w/o Solid Fill. Refer to PDRs#5511/6817.
  35. *
  36. * sge01 11/26/96 Use second aperture when doing 24bpp cache blt.
  37. *
  38. *
  39. \******************************************************************************/
  40. #include "precomp.h"
  41. //bc#1 Handy macros.
  42. #define BUSY_BLT(ppdev, pjBase) (CP_MM_ACL_STAT(ppdev, pjBase) & 0x10)
  43. /******************************Public*Routine******************************\
  44. * VOID vRealizeDitherPattern
  45. *
  46. * Generates an 8x8 dither pattern, in our internal realization format, for
  47. * the color ulRGBToDither. Note that the high byte of ulRGBToDither does
  48. * not need to be set to zero, because vComputeSubspaces ignores it.
  49. \**************************************************************************/
  50. VOID vRealizeDitherPattern(
  51. RBRUSH* prb,
  52. ULONG ulRGBToDither)
  53. {
  54. ULONG ulNumVertices;
  55. VERTEX_DATA vVertexData[4];
  56. VERTEX_DATA* pvVertexData;
  57. // Calculate what color subspaces are involved in the dither:
  58. pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData);
  59. // Now that we have found the bounding vertices and the number of
  60. // pixels to dither for each vertex, we can create the dither pattern
  61. ulNumVertices = (ULONG)(pvVertexData - vVertexData);
  62. // # of vertices with more than zero pixels in the dither
  63. // Do the actual dithering:
  64. vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices);
  65. // Initialize the fields we need:
  66. prb->ptlBrushOrg.x = LONG_MIN;
  67. prb->fl = 0;
  68. prb->pbe = NULL;
  69. }
  70. /******************************Public*Routine******************************\
  71. * BOOL DrvRealizeBrush
  72. *
  73. * This function allows us to convert GDI brushes into an internal form
  74. * we can use. It may be called directly by GDI at SelectObject time, or
  75. * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
  76. * to create a realized brush in a function like DrvBitBlt.
  77. *
  78. * Note that we have no way of determining what the current Rop or brush
  79. * alignment are at this point.
  80. *
  81. \**************************************************************************/
  82. BOOL DrvRealizeBrush(
  83. BRUSHOBJ* pbo,
  84. SURFOBJ* psoDst,
  85. SURFOBJ* psoPattern,
  86. SURFOBJ* psoMask,
  87. XLATEOBJ* pxlo,
  88. ULONG iHatch)
  89. {
  90. ULONG iPatternFormat;
  91. BYTE* pjSrc;
  92. BYTE* pjDst;
  93. LONG lSrcDelta;
  94. LONG cj;
  95. LONG i;
  96. LONG j;
  97. RBRUSH* prb;
  98. ULONG* pulXlate;
  99. SURFOBJ* psoPunt;
  100. RECTL rclDst;
  101. FLONG flXlate; //bc#1
  102. PDEV* ppdev = (PPDEV)psoDst->dhpdev;
  103. #if 1 //bc#1 Dither cache.
  104. // Dithers...
  105. if (iHatch & RB_DITHERCOLOR)
  106. {
  107. if (ppdev->flStatus & STAT_DITHER_CACHE)
  108. {
  109. DITHERCACHE* pdc;
  110. ULONG ulColor;
  111. // Save the color.
  112. ulColor = iHatch & 0xFFFFFF;
  113. // Allocate the brush.
  114. prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH));
  115. if (prb == NULL)
  116. {
  117. DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
  118. return(FALSE);
  119. }
  120. // Set the dithered brush flags.
  121. prb->fl = RBRUSH_DITHER;
  122. prb->ulUniq = ulColor;
  123. // Look for a match with the cached dithers.
  124. pdc = &ppdev->aDithers[0];
  125. for (i = 0; i < NUM_DITHERS; i++)
  126. {
  127. if (pdc->ulColor == ulColor)
  128. {
  129. // We have a match, just set the brush pointers.
  130. DISPDBG((20, "DrvRealizeBrush: DitherCache match (0x%06X)",
  131. ulColor));
  132. prb->ulSlot = (ULONG)((ULONG_PTR)pdc - (ULONG_PTR)ppdev);
  133. prb->ulBrush = pdc->ulBrush;
  134. return(TRUE);
  135. }
  136. pdc++;
  137. }
  138. // Create the dither and cache it.
  139. return(bCacheDither(ppdev, prb));
  140. }
  141. if (!(ppdev->flStatus & (STAT_BRUSH_CACHE | STAT_PATTERN_CACHE)))
  142. {
  143. DISPDBG((2, "DrvRealizeBrush: No brush cache to create dither"));
  144. return(FALSE);
  145. }
  146. // Allocate the brush.
  147. prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) +
  148. PELS_TO_BYTES(TOTAL_BRUSH_SIZE));
  149. if (prb == NULL)
  150. {
  151. DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
  152. return(FALSE);
  153. }
  154. // Realize the dither.
  155. vRealizeDitherPattern(prb, iHatch);
  156. if (ppdev->flStatus & STAT_PATTERN_CACHE)
  157. {
  158. prb->cjBytes = PELS_TO_BYTES(8) * 8;
  159. prb->ulSlot = 0;
  160. return(bCachePattern(ppdev, prb));
  161. }
  162. return(TRUE);
  163. }
  164. #endif
  165. // We only accelerate 8x8 patterns.
  166. if ((psoPattern->sizlBitmap.cx != 8) || (psoPattern->sizlBitmap.cy != 8))
  167. {
  168. DISPDBG((2, "DrvRealizeBrush: psoPattern too big (%d x %d)",
  169. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  170. return(FALSE);
  171. }
  172. // We don't support masks just yet.
  173. if ((psoMask != NULL) && (psoMask->pvScan0 != psoPattern->pvScan0))
  174. {
  175. DISPDBG((2, "DrvRealizeBrush: psoMask not supported"));
  176. return(FALSE);
  177. }
  178. // Get the brush type.
  179. iPatternFormat = psoPattern->iBitmapFormat;
  180. if (psoPattern->iType != STYPE_BITMAP)
  181. {
  182. DISPDBG((2, "DrvRealizeBrush: psoPattern->iType (=%d) not supported",
  183. psoPattern->iType));
  184. return(FALSE);
  185. }
  186. // Get the color translation table.
  187. flXlate = (pxlo == NULL) ? XO_TRIVIAL : pxlo->flXlate;
  188. if (flXlate & XO_TRIVIAL)
  189. {
  190. pulXlate = NULL;
  191. }
  192. else if (flXlate & XO_TABLE)
  193. {
  194. pulXlate = pxlo->pulXlate;
  195. }
  196. else
  197. {
  198. pulXlate = XLATEOBJ_piVector(pxlo);
  199. }
  200. #if 1 //bc#1 Monochrome cache.
  201. if ((iPatternFormat == BMF_1BPP) &&
  202. (ppdev->flStatus & STAT_MONOCHROME_CACHE))
  203. {
  204. MONOCACHE* pmc;
  205. // We need a translation table.
  206. if (pulXlate == NULL)
  207. {
  208. DISPDBG((2, "DrvRealizeBrush: psoPattern(monochrome) pxlo=NULL"));
  209. return(FALSE);
  210. }
  211. // Allocate the brush.
  212. prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) + 8);
  213. if (prb == NULL)
  214. {
  215. DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
  216. return(FALSE);
  217. }
  218. // Initialize the realized brush.
  219. prb->fl = RBRUSH_MONOCHROME;
  220. prb->ulBackColor = pulXlate[0];
  221. prb->ulForeColor = pulXlate[1];
  222. pjSrc = psoPattern->pvScan0;
  223. lSrcDelta = psoPattern->lDelta;
  224. // Copy the pattern to the realized brush.
  225. for (i = 0; i < 8; i++)
  226. {
  227. ((BYTE*) prb->aulPattern)[i] = *pjSrc;
  228. pjSrc += lSrcDelta;
  229. }
  230. // Lookup the pattern in te monochrome cache.
  231. pmc = &ppdev->aMonochromes[0];
  232. if (ppdev->cBpp == 3)
  233. {
  234. for (i = 0; i < NUM_MONOCHROMES; i++)
  235. {
  236. if ((pmc->aulPattern[0] == prb->aulPattern[0]) &&
  237. (pmc->aulPattern[1] == prb->aulPattern[1]) &&
  238. (pmc->ulBackColor == prb->ulBackColor) &&
  239. (pmc->ulForeColor == prb->ulForeColor))
  240. {
  241. // We have a match! Just copy the brush pointers.
  242. DISPDBG((20, "DrvRealizeBrush: Monochrome hit"));
  243. prb->ulUniq = pmc->ulUniq;
  244. prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
  245. prb->ulBrush = pmc->ulBrush;
  246. return(TRUE);
  247. }
  248. pmc++;
  249. }
  250. }
  251. else
  252. {
  253. for (i = 0; i < NUM_MONOCHROMES; i++)
  254. {
  255. if ((pmc->aulPattern[0] == prb->aulPattern[0]) &&
  256. (pmc->aulPattern[1] == prb->aulPattern[1]))
  257. {
  258. // We have a match! Just copy the brush pointers.
  259. DISPDBG((20, "DrvRealizeBrush: Monochrome hit"));
  260. prb->ulUniq = pmc->ulUniq;
  261. prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
  262. prb->ulBrush = pmc->ulBrush;
  263. return(TRUE);
  264. }
  265. pmc++;
  266. }
  267. }
  268. return(bCacheMonochrome(ppdev, prb));
  269. }
  270. #endif
  271. // We must have either an old-style brush cache or a new-style pattern
  272. // cache to continue.
  273. if (!(ppdev->flStatus & (STAT_BRUSH_CACHE | STAT_PATTERN_CACHE)))
  274. {
  275. DISPDBG((2, "DrvRealizeBrush: No brush cache"));
  276. return(FALSE);
  277. }
  278. // Allocate the brush.
  279. prb = BRUSHOBJ_pvAllocRbrush(pbo, sizeof(RBRUSH) +
  280. PELS_TO_BYTES(TOTAL_BRUSH_SIZE));
  281. if (prb == NULL)
  282. {
  283. DISPDBG((2, "DrvRealizeBrush: BRUSHOBJ_pvAllocRbrush failed"));
  284. return(FALSE);
  285. }
  286. // Initialize the realized brush.
  287. prb->ptlBrushOrg.x = LONG_MIN;
  288. prb->fl = RBRUSH_PATTERN;
  289. prb->pbe = NULL;
  290. lSrcDelta = psoPattern->lDelta;
  291. pjSrc = (BYTE*) psoPattern->pvScan0;
  292. pjDst = (BYTE*) &prb->aulPattern[0];
  293. //bc#1
  294. if ((ppdev->iBitmapFormat == iPatternFormat) && (flXlate & XO_TRIVIAL))
  295. {
  296. // The pattern is the same color depth as the screen, and there's no
  297. // translation to be done.
  298. cj = PELS_TO_BYTES(8);
  299. // Copy the pattern to the realized brush.
  300. for (i = 8; i != 0; i--)
  301. {
  302. RtlCopyMemory(pjDst, pjSrc, cj);
  303. pjSrc += lSrcDelta;
  304. pjDst += cj;
  305. }
  306. }
  307. else if ((iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  308. {
  309. // Translate the 16-color brush.
  310. for (i = 8; i != 0; i--)
  311. {
  312. // Inner loop is repeated only 4 times because each loop handles 2
  313. // pixels.
  314. for (j = 4; j != 0; j--)
  315. {
  316. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  317. *pjDst++ = (BYTE) pulXlate[*pjSrc & 0x0F];
  318. pjSrc++;
  319. }
  320. pjSrc += lSrcDelta - 4;
  321. }
  322. }
  323. else
  324. {
  325. // We've got a brush whose format we haven't special cased. No problem,
  326. // we can have GDI convert it to our device's format. We simply use a
  327. // temporary surface object that was created with the same format as
  328. // the display, and point it to our brush realization.
  329. psoPunt = ppdev->psoBank;
  330. psoPunt->pvScan0 = pjDst;
  331. psoPunt->lDelta = PELS_TO_BYTES(8);
  332. rclDst.left = 0;
  333. rclDst.top = 0;
  334. rclDst.right = 8;
  335. rclDst.bottom = 8;
  336. if (!EngCopyBits(psoPunt, psoPattern, NULL, pxlo, &rclDst,
  337. (POINTL*) &rclDst))
  338. {
  339. DISPDBG((2, "DrvRealizeBrush: Unable to create funky brush"));
  340. return(FALSE);
  341. }
  342. }
  343. #if 1 //bc#1
  344. // If we have a pattern cache, cache the brush now.
  345. if (ppdev->flStatus & STAT_PATTERN_CACHE)
  346. {
  347. prb->cjBytes = PELS_TO_BYTES(8) * 8;
  348. return(bCachePattern(ppdev, prb));
  349. }
  350. #endif
  351. return(TRUE);
  352. }
  353. /******************************Public*Routine******************************\
  354. * BOOL bEnableBrushCache
  355. *
  356. * Allocates off-screen memory for storing the brush cache.
  357. \**************************************************************************/
  358. BOOL bEnableBrushCache(
  359. PDEV* ppdev)
  360. {
  361. OH* poh; // Points to off-screen chunk of memory
  362. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  363. LONG i;
  364. LONG cBrushAlign; // 0 = no alignment,
  365. // n = align to n pixels
  366. LONG x;
  367. LONG y;
  368. #if 1 //bc#1 Dither cache.
  369. if ((ppdev->cBpp == 1) &&
  370. (ppdev->flCaps & CAPS_AUTOSTART) &&
  371. (ppdev->bLinearMode))
  372. {
  373. LONG lDelta;
  374. // Allocate the dither cache horizontally.
  375. poh = pohAllocatePermanent(ppdev, 64 * NUM_DITHERS + 63, 1);
  376. lDelta = 64;
  377. if (poh == NULL)
  378. {
  379. // Allocate the dither cache vertically.
  380. poh = pohAllocatePermanent(ppdev, 64 + 63, NUM_DITHERS);
  381. lDelta = ppdev->lDelta;
  382. }
  383. if (poh != NULL)
  384. {
  385. // Align the cache to a 64-byte boundary.
  386. ULONG ulBase = (poh->xy + 63) & ~63;
  387. // Initialize the dither cache.
  388. DISPDBG((4, "DitherCache allocated at %d,%d (%d x %d)",
  389. poh->x, poh->y, poh->cx, poh->cy));
  390. for (i = 0; i < NUM_DITHERS; i++)
  391. {
  392. ppdev->aDithers[i].ulColor = (ULONG) -1;
  393. ppdev->aDithers[i].ulBrush = ulBase;
  394. ulBase += lDelta;
  395. }
  396. // The dither cache has been initialized.
  397. ppdev->iDitherCache = 0;
  398. ppdev->flStatus |= STAT_DITHER_CACHE;
  399. }
  400. }
  401. #endif
  402. #if 1 //bc#1 Pattern cache.
  403. if ((ppdev->flCaps & CAPS_AUTOSTART) &&
  404. (ppdev->bLinearMode))
  405. {
  406. LONG lDelta;
  407. LONG cBrushSize;
  408. ULONG ulAlignment;
  409. // Calculate the width of brush in pixels.
  410. if (ppdev->cBpp == 3)
  411. {
  412. cBrushSize = (256 + 2) / 3;
  413. ulAlignment = 256;
  414. }
  415. else
  416. {
  417. cBrushSize = 64;
  418. ulAlignment = PELS_TO_BYTES(64);
  419. }
  420. // Allocate the pattern cache horizontally.
  421. poh = pohAllocatePermanent(ppdev, cBrushSize * NUM_PATTERNS +
  422. (cBrushSize - 1), 1);
  423. lDelta = ulAlignment;
  424. if (poh == NULL)
  425. {
  426. // Allocate the pattern cache vertically.
  427. poh = pohAllocatePermanent(ppdev, cBrushSize + (cBrushSize - 1),
  428. NUM_PATTERNS);
  429. lDelta = ppdev->lDelta;
  430. }
  431. if (poh != NULL)
  432. {
  433. // Align the cache to a 64-pixel boundary.
  434. ULONG ulBase = (poh->xy + (ulAlignment - 1)) & ~(ulAlignment - 1);
  435. // Initialize the pattern cache.
  436. DISPDBG((4, "PatternCache allocated at %d,%d (%d x %d)",
  437. poh->x, poh->y, poh->cx, poh->cy));
  438. for (i = 0; i < NUM_PATTERNS; i++)
  439. {
  440. ppdev->aPatterns[i].ulBrush = ulBase;
  441. ppdev->aPatterns[i].prbUniq = NULL;
  442. ulBase += lDelta;
  443. }
  444. // The pattern cache has been initialized.
  445. ppdev->iPatternCache = 0;
  446. ppdev->flStatus |= STAT_PATTERN_CACHE;
  447. }
  448. }
  449. #endif
  450. #if 1 //bc#1 Monochrome cache.
  451. if ((ppdev->flCaps & CAPS_AUTOSTART) &&
  452. (ppdev->bLinearMode))
  453. {
  454. LONG lDelta;
  455. LONG cBrushSize;
  456. ULONG ulAlignment;
  457. // Calculate the width of brush in pixels.
  458. if (ppdev->cBpp == 3)
  459. {
  460. cBrushSize = (256 + 2) / 3;
  461. ulAlignment = 256;
  462. }
  463. else
  464. {
  465. cBrushSize = BYTES_TO_PELS(8);
  466. ulAlignment = 8;
  467. }
  468. // Allocate the pattern cache horizontally.
  469. poh = pohAllocatePermanent(ppdev, cBrushSize * NUM_MONOCHROMES +
  470. (cBrushSize - 1), 1);
  471. lDelta = ulAlignment;
  472. if (poh == NULL)
  473. {
  474. // Allocate the pattern cache vertically.
  475. poh = pohAllocatePermanent(ppdev, cBrushSize + (cBrushSize - 1),
  476. NUM_MONOCHROMES);
  477. lDelta = ppdev->lDelta;
  478. }
  479. if (poh != NULL)
  480. {
  481. // Align the cache to an 8-byte boundary.
  482. ULONG ulBase = (poh->xy + (ulAlignment - 1)) & ~(ulAlignment - 1);
  483. // Initialize the monochrome cache.
  484. DISPDBG((4, "MonochromeCache allocated at %d,%d (%d x %d)",
  485. poh->x, poh->y, poh->cx, poh->cy));
  486. for (i = 0; i < NUM_MONOCHROMES; i++)
  487. {
  488. ppdev->aMonochromes[i].ulBrush = ulBase;
  489. ppdev->aMonochromes[i].aulPattern[0] = 0;
  490. ppdev->aMonochromes[i].aulPattern[1] = 0;
  491. ulBase += lDelta;
  492. }
  493. // The monochrome cache has been initialized.
  494. ppdev->iMonochromeCache = 0;
  495. ppdev->flStatus |= STAT_MONOCHROME_CACHE;
  496. }
  497. }
  498. #endif
  499. cBrushAlign = 64; // Align all brushes to 64 pixels
  500. DISPDBG((2, "cBrushAlign = %d", cBrushAlign));
  501. pbe = &ppdev->abe[0]; // Points to where we'll put the first
  502. // brush cache entry
  503. {
  504. // Reserve the offscreen space that is required for the CP to do
  505. // solid fills. If this fails, our solid fill code will not work.
  506. // We need two DWORD storage locations if we're going to do any
  507. // monochrome expansion stuff (font painting...).
  508. // Note: these must be 8 byte aligned for the cirrus chips
  509. // Not having a solid color work area is a
  510. // fatal error for this driver.
  511. DISPDBG((2,"Allocating solid brush work area"));
  512. poh = pohAllocatePermanent(ppdev, 16, 1);
  513. ASSERTDD((poh != NULL),
  514. "We couldn't allocate offscreen space for the solid colors");
  515. ppdev->ulSolidColorOffset = ((((poh->y * ppdev->lDelta) +
  516. PELS_TO_BYTES(poh->x)) + 7) & ~7);
  517. DISPDBG((2,"ppdev->ulSolidColorOffset = %xh", ppdev->ulSolidColorOffset));
  518. #if 1 //bc#1 Only one pattern cache.
  519. if (ppdev->flStatus & STAT_PATTERN_CACHE)
  520. {
  521. goto ReturnTrue;
  522. }
  523. #endif
  524. ///////////////////////////////////////////////////////////////////////
  525. // Special cases where we want no brush cache...
  526. //
  527. // There are a couple of instances where we have no xfer buffer to
  528. // the HW blt engine. In that case, we are unable to realize
  529. // patterns, so don't enable the cache.
  530. //
  531. // (1) NEC Mips nachines lock up on xfers, so they're diabled.
  532. // (2) At 1280x1024 on a 2MB card, we currently have no room for
  533. // the buffer because of stretched scans. This will be fixed.
  534. {
  535. if (ppdev->pulXfer == NULL)
  536. goto ReturnTrue;
  537. }
  538. //
  539. // Allocate single brush location for intermediate alignment purposes
  540. //
  541. #if 1 //bc#1
  542. if (ppdev->cBpp == 3)
  543. {
  544. poh = pohAllocatePermanent(ppdev,
  545. (8 * 8 * 4) / 3 + (cBrushAlign - 1), 1);
  546. }
  547. else
  548. #endif
  549. {
  550. poh = pohAllocatePermanent(ppdev, (8 * 8) + (cBrushAlign - 1), 1);
  551. }
  552. if (poh == NULL)
  553. {
  554. DISPDBG((2,"Failed to allocate aligned brush area"));
  555. goto ReturnTrue; // See note about why we can return TRUE...
  556. }
  557. ppdev->ulAlignedPatternOffset = ((poh->xy) +
  558. (PELS_TO_BYTES(cBrushAlign) - 1)) &
  559. ~(PELS_TO_BYTES(cBrushAlign) - 1);
  560. DISPDBG((2,"ppdev->ulAlignedPatternOffset = %xh", ppdev->ulAlignedPatternOffset));
  561. //
  562. // Allocate brush cache
  563. //
  564. #if 1 //bc#1
  565. if (ppdev->cBpp == 3)
  566. {
  567. poh = pohAllocatePermanent(ppdev,
  568. (BRUSH_TILE_FACTOR * 8 * 8 * 4) / 3 + cBrushAlign - 1,
  569. FAST_BRUSH_COUNT);
  570. }
  571. else
  572. #endif
  573. {
  574. poh = pohAllocatePermanent(ppdev,
  575. // remember this is pixels, not bytes
  576. (BRUSH_TILE_FACTOR * 8 * 8) + (cBrushAlign - 1),
  577. FAST_BRUSH_COUNT);
  578. }
  579. if (poh == NULL)
  580. {
  581. DISPDBG((2,"Failed to allocate brush cache"));
  582. goto ReturnTrue; // See note about why we can return TRUE...
  583. }
  584. ppdev->cBrushCache = FAST_BRUSH_COUNT;
  585. // Hardware brushes require that the bits start on a 64 (height*width)
  586. // pixel boundary. The heap manager doesn't guarantee us any such
  587. // alignment, so we allocate a bit of extra room so that we can
  588. // do the alignment ourselves:
  589. x = poh->x;
  590. y = poh->y;
  591. for (i = FAST_BRUSH_COUNT; i != 0; i--)
  592. {
  593. ULONG ulOffset;
  594. ULONG ulCeil;
  595. ULONG ulDiff;
  596. // Note: I learned the HARD way that you can't just align x
  597. // to your pattern size, because the lDelta of your screen
  598. // is not guaranteed to be a multiple of your pattern size.
  599. // Since y is changing in this loop, the recalc must
  600. // be done inside this loop. I really need to set these
  601. // up with a hardcoded linear buffer or else make the
  602. // heap linear.
  603. ulOffset = (y * ppdev->lDelta) + PELS_TO_BYTES(x);
  604. ulCeil = (ulOffset + (PELS_TO_BYTES(cBrushAlign)-1)) & ~(PELS_TO_BYTES(cBrushAlign)-1);
  605. ulDiff = (ulCeil - ulOffset)/ppdev->cBpp;
  606. // If we hadn't allocated 'ppdev' with FL_ZERO_MEMORY,
  607. // we would have to initialize pbe->prbVerify too...
  608. pbe->x = x + ulDiff;
  609. pbe->y = y;
  610. pbe->xy = (pbe->y * ppdev->lDelta) + PELS_TO_BYTES(pbe->x);
  611. DISPDBG((2, "BrushCache[%d] pos(%d,%d) offset(%d)", i, pbe->x,
  612. pbe->y, pbe->xy ));
  613. y++;
  614. pbe++;
  615. }
  616. }
  617. // Note that we don't have to remember 'poh' for when we have
  618. // to disable brushes -- the off-screen heap frees any
  619. // off-screen heap allocations automatically.
  620. // We successfully allocated the brush cache, so let's turn
  621. // on the switch showing that we can use it:
  622. ppdev->flStatus |= STAT_BRUSH_CACHE;
  623. ReturnTrue:
  624. // If we couldn't allocate a brush cache, it's not a catastrophic
  625. // failure; patterns will still work, although they'll be a bit
  626. // slower since they'll go through GDI. As a result we don't
  627. // actually have to fail this call:
  628. vAssertModeBrushCache(ppdev, TRUE);
  629. DISPDBG((5, "Passed bEnableBrushCache"));
  630. return(TRUE);
  631. }
  632. /******************************Public*Routine******************************\
  633. * VOID vDisableBrushCache
  634. *
  635. * Cleans up anything done in bEnableBrushCache.
  636. \**************************************************************************/
  637. VOID vDisableBrushCache(PDEV* ppdev)
  638. {
  639. // We ain't gotta do nothin'
  640. }
  641. /******************************Public*Routine******************************\
  642. * VOID vAssertModeBrushCache
  643. *
  644. * Resets the brush cache when we exit out of full-screen.
  645. \**************************************************************************/
  646. VOID vAssertModeBrushCache(
  647. PDEV* ppdev,
  648. BOOL bEnable)
  649. {
  650. BRUSHENTRY* pbe;
  651. LONG i;
  652. if (bEnable)
  653. {
  654. //bc#1 Invalidate the dither cache.
  655. if (ppdev->flStatus & STAT_DITHER_CACHE)
  656. {
  657. for (i = 0; i < NUM_DITHERS; i++)
  658. {
  659. ppdev->aDithers[i].ulColor = (ULONG) -1;
  660. }
  661. }
  662. //bc#1 Invalidate the pattern cache.
  663. if (ppdev->flStatus & STAT_PATTERN_CACHE)
  664. {
  665. for (i = 0; i < NUM_PATTERNS; i++)
  666. {
  667. ppdev->aPatterns[i].prbUniq = NULL;
  668. }
  669. }
  670. //bc#1 Invalidate the monochrome cache.
  671. if (ppdev->flStatus & STAT_MONOCHROME_CACHE)
  672. {
  673. for (i = 0; i < NUM_MONOCHROMES; i++)
  674. {
  675. ppdev->aMonochromes[i].ulUniq = 0;
  676. ppdev->aMonochromes[i].aulPattern[0] = 0;
  677. ppdev->aMonochromes[i].aulPattern[1] = 0;
  678. }
  679. }
  680. // Invalidate the brush cache.
  681. if (ppdev->flStatus & STAT_BRUSH_CACHE)
  682. {
  683. pbe = &ppdev->abe[0];
  684. for (i = ppdev->cBrushCache; i != 0; i--)
  685. {
  686. pbe->prbVerify = NULL;
  687. pbe++;
  688. }
  689. }
  690. // Create a solid 8 x 8 monochrome bitmap in offscreen memory which
  691. // will be used for solid fills.
  692. if (ppdev->flCaps & CAPS_MM_IO)
  693. {
  694. BYTE* pjBase = ppdev->pjBase;
  695. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  696. CP_MM_XCNT(ppdev, pjBase, 7);
  697. CP_MM_YCNT(ppdev, pjBase, 0);
  698. CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
  699. CP_MM_BLT_MODE(ppdev, pjBase, 0);
  700. CP_MM_ROP(ppdev, pjBase, CL_WHITENESS);
  701. CP_MM_DST_ADDR_ABS(ppdev, pjBase, ppdev->ulSolidColorOffset);
  702. CP_MM_START_BLT(ppdev, pjBase);
  703. }
  704. else
  705. {
  706. BYTE* pjPorts = ppdev->pjPorts;
  707. CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
  708. CP_IO_XCNT(ppdev, pjPorts, 7);
  709. CP_IO_YCNT(ppdev, pjPorts, 0);
  710. CP_IO_BLT_MODE(ppdev, pjPorts, 0);
  711. CP_IO_ROP(ppdev, pjPorts, CL_WHITENESS);
  712. CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ppdev->ulSolidColorOffset);
  713. CP_IO_START_BLT(ppdev, pjPorts);
  714. }
  715. }
  716. }
  717. ////////////////////////////////////////////////////////////////////////////////
  718. // //
  719. // B R U S H C A C H E S T U F F //
  720. // //
  721. ////////////////////////////////////////////////////////////////////////////////
  722. /*
  723. Dither Cache:
  724. ============
  725. The dither cache is very important (at least with a slow CPU). Since the
  726. dithering process (in 8-bpp) takes quite a long time we must somehow cache
  727. the dithering process so it doesn't have to be executed over and over again.
  728. We do this by comparing the requested logical color with the cached dithers.
  729. If we have a match we simply copy the cached parameters and return. If we
  730. don't have a match we create a new cache slot and create the dither in
  731. off-screen memory.
  732. Pattern Cache:
  733. =============
  734. The pattern cache holds the colored brushes. Whenever we are requested to
  735. realize the same brush again, we can simply return. We don't check for the
  736. brush bits since that will take up too much time.
  737. Monochrome Cache:
  738. ================
  739. The monochrome cache holds the monochrome brushes. Whenever a monochrome
  740. brush needs to be realized we check to see if it is already cached
  741. off-screen. If it is we simply copy the cached parameters and return.
  742. Otherwise we have to create a new cache slot and realize the monochrome
  743. brush directly in off-screen memory. This has a slight performance hit since
  744. the bitblt engine is interrupted (on CL5436) or must be idle (in 24-bpp).
  745. Translation Cache:
  746. =================
  747. Is not yet implemented.
  748. */
  749. /******************************************************************************\
  750. *
  751. * Function: bCacheDither
  752. *
  753. * Cache a dithered color.
  754. *
  755. * Parameters: ppdev Pointer to physicsl device.
  756. * prb Pointer to physical brush.
  757. *
  758. * Returns: TRUE.
  759. *
  760. \******************************************************************************/
  761. BOOL bCacheDither(
  762. PDEV* ppdev,
  763. RBRUSH* prb)
  764. {
  765. ULONG ulNumVertices;
  766. VERTEX_DATA vVertexData[4];
  767. VERTEX_DATA* pvVertexData;
  768. DITHERCACHE* pdc;
  769. ULONG ulIndex;
  770. // New dither cache entry.
  771. ulIndex = ppdev->iDitherCache++ % NUM_DITHERS;
  772. pdc = &ppdev->aDithers[ulIndex];
  773. // Store the color in the cache slot.
  774. pdc->ulColor = prb->ulUniq;
  775. // Update the brush cache variables.
  776. prb->ulSlot = (ULONG)((ULONG_PTR)pdc - (ULONG_PTR)ppdev);
  777. prb->ulBrush = pdc->ulBrush;
  778. // Create the dither.
  779. pvVertexData = vComputeSubspaces(prb->ulUniq, vVertexData);
  780. ulNumVertices = (ULONG)(pvVertexData - vVertexData);
  781. vDitherColorToVideoMemory((ULONG*) (ppdev->pjScreen + pdc->ulBrush), vVertexData,
  782. pvVertexData, ulNumVertices);
  783. DISPDBG((20, "Caching dithered brush ulIndex=%d ulColor=%06X",
  784. ulIndex, pdc->ulColor));
  785. return(TRUE);
  786. }
  787. /******************************************************************************\
  788. *
  789. * Function: bCacheColor
  790. *
  791. * Cache a patterned brush.
  792. *
  793. * Parameters: ppdev Pointer to physicsl device.
  794. * prb Pointer to physical brush.
  795. *
  796. * Returns: TRUE.
  797. *
  798. \******************************************************************************/
  799. BOOL bCachePattern(
  800. PDEV* ppdev,
  801. RBRUSH* prb
  802. )
  803. {
  804. PATTERNCACHE* ppc;
  805. LONG lDstDelta;
  806. SIZEL sizlDst;
  807. ULONG* pulSrc;
  808. LONG i;
  809. ULONG* pulDst;
  810. ULONG ulIndex;
  811. BYTE* pjBase = ppdev->pjBase;
  812. // New pattern cache entry.
  813. ulIndex = ppdev->iPatternCache++ % NUM_PATTERNS;
  814. ppc = &ppdev->aPatterns[ulIndex];
  815. // Update the brush cache variables.
  816. ppc->prbUniq = prb;
  817. prb->ulSlot = (ULONG)((ULONG_PTR)ppc - (ULONG_PTR)ppdev);
  818. prb->ulBrush = ppc->ulBrush;
  819. // Calculate the sizes for the pattern.
  820. pulSrc = prb->aulPattern;
  821. pulDst = (ULONG*) ppdev->pulXfer;
  822. lDstDelta = (ppdev->cBpp == 3) ? (8 * 4) : PELS_TO_BYTES(8);
  823. sizlDst.cx = PELS_TO_BYTES(8) - 1;
  824. sizlDst.cy = 8 - 1;
  825. // Wait for the bitblt engine.
  826. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  827. // Setup the blit registers.
  828. CP_MM_XCNT(ppdev, pjBase, sizlDst.cx);
  829. CP_MM_YCNT(ppdev, pjBase, sizlDst.cy);
  830. CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDstDelta);
  831. CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
  832. CP_MM_BLT_MODE(ppdev, pjBase, SRC_CPU_DATA);
  833. CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY);
  834. CP_MM_DST_ADDR_ABS(ppdev, pjBase, ppc->ulBrush);
  835. // Copy the brush to off-screen cache memory.
  836. for (i = prb->cjBytes; i > 0; i -= sizeof(ULONG))
  837. {
  838. WRITE_REGISTER_ULONG(pulDst, *pulSrc++);
  839. }
  840. DISPDBG((20, "Caching patterned brush at slot %d", ulIndex));
  841. return(TRUE);
  842. }
  843. /******************************************************************************\
  844. *
  845. * Function: bCacheMonochrome
  846. *
  847. * Cache a monochrome brush.
  848. *
  849. * Parameters: ppdev Pointer to physicsl device.
  850. * prb Pointer to physical brush.
  851. *
  852. * Returns: TRUE.
  853. *
  854. \******************************************************************************/
  855. BOOL bCacheMonochrome(
  856. PDEV* ppdev,
  857. RBRUSH* prb
  858. )
  859. {
  860. MONOCACHE* pmc;
  861. ULONG ulIndex;
  862. BYTE* pjDst;
  863. ULONG* pulDst;
  864. // New monochrome cache entry.
  865. ulIndex = ppdev->iMonochromeCache++ % NUM_MONOCHROMES;
  866. pmc = &ppdev->aMonochromes[ulIndex];
  867. // Update the brush cache variables.
  868. pmc->aulPattern[0] = prb->aulPattern[0];
  869. pmc->aulPattern[1] = prb->aulPattern[1];
  870. pmc->ulUniq = ppdev->iMonochromeCache;
  871. prb->ulUniq = ppdev->iMonochromeCache;
  872. prb->ulSlot = (ULONG)((ULONG_PTR)pmc - (ULONG_PTR)ppdev);
  873. prb->ulBrush = pmc->ulBrush;
  874. // Copy the brush to off-screen cache memory.
  875. if (ppdev->cBpp == 3)
  876. {
  877. BYTE* pjBase = ppdev->pjBase;
  878. // Copy colors to brush cache.
  879. pmc->ulBackColor = prb->ulBackColor;
  880. pmc->ulForeColor = prb->ulForeColor;
  881. pulDst = (ULONG*)ppdev->pulXfer;
  882. // Wait for bitblt engine.
  883. while (BUSY_BLT(ppdev, pjBase));
  884. // Fill the background.
  885. CP_MM_FG_COLOR(ppdev, pjBase, pmc->ulBackColor);
  886. CP_MM_XCNT(ppdev, pjBase, (8 * 3) - 1);
  887. CP_MM_YCNT(ppdev, pjBase, (8) - 1);
  888. CP_MM_DST_Y_OFFSET(ppdev, pjBase, 8 * 4);
  889. CP_MM_DST_WRITE_MASK(ppdev, pjBase, 0);
  890. CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND |
  891. ENABLE_8x8_PATTERN_COPY |
  892. SET_24BPP_COLOR);
  893. CP_MM_ROP(ppdev, pjBase, CL_SRC_COPY);
  894. CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL);
  895. CP_MM_DST_ADDR_ABS(ppdev, pjBase, pmc->ulBrush);
  896. // Wait for bitblt engine.
  897. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);
  898. // Expand the pattern.
  899. CP_MM_FG_COLOR(ppdev, pjBase, pmc->ulForeColor);
  900. CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND |
  901. SET_24BPP_COLOR |
  902. ENABLE_TRANSPARENCY_COMPARE |
  903. SRC_CPU_DATA);
  904. CP_MM_BLT_EXT_MODE(ppdev, pjBase, 0) // jl01
  905. CP_MM_DST_ADDR_ABS(ppdev, pjBase, pmc->ulBrush);
  906. WRITE_REGISTER_ULONG(pulDst, pmc->aulPattern[0]);
  907. WRITE_REGISTER_ULONG(pulDst, pmc->aulPattern[1]);
  908. }
  909. else
  910. {
  911. pulDst = (ULONG *)(ppdev->pjScreen + prb->ulBrush);
  912. WRITE_REGISTER_ULONG(pulDst++, prb->aulPattern[0]);
  913. WRITE_REGISTER_ULONG(pulDst, prb->aulPattern[1]);
  914. }
  915. DISPDBG((20, "Caching monochrome brush ulIndex=%d pattern=%08X%08X",
  916. ulIndex, prb->aulPattern[0], prb->aulPattern[1]));
  917. return(TRUE);
  918. }