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.

583 lines
19 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: Brush.c
  3. *
  4. * Handles all brush/pattern initialization and realization.
  5. *
  6. * Copyright (c) 1992-1996 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. #include "precomp.h"
  10. /******************************Public*Routine******************************\
  11. * VOID vRealizeDitherPattern
  12. *
  13. * Generates an 8x8 dither pattern, in our internal realization format, for
  14. * the color ulRGBToDither. Note that the high byte of ulRGBToDither does
  15. * not need to be set to zero, because vComputeSubspaces ignores it.
  16. \**************************************************************************/
  17. VOID vRealizeDitherPattern(
  18. RBRUSH* prb,
  19. ULONG ulRGBToDither,
  20. ULONG cTile)
  21. {
  22. ULONG ulNumVertices;
  23. VERTEX_DATA vVertexData[4];
  24. VERTEX_DATA* pvVertexData;
  25. LONG i;
  26. // Calculate what color subspaces are involved in the dither:
  27. pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData);
  28. // Now that we have found the bounding vertices and the number of
  29. // pixels to dither for each vertex, we can create the dither pattern
  30. ulNumVertices = (ULONG)(pvVertexData - vVertexData);
  31. // # of vertices with more than zero pixels in the dither
  32. // Do the actual dithering:
  33. vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices);
  34. if (cTile)
  35. {
  36. BYTE* pjDst = (BYTE*)&prb->aulPattern[0];
  37. // Probably another version of vDitherColor is
  38. // in order.
  39. i = 56; // start with last row of 8x8
  40. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  41. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  42. i -= 8;
  43. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  44. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  45. i -= 8;
  46. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  47. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  48. i -= 8;
  49. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  50. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  51. i -= 8;
  52. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  53. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  54. i -= 8;
  55. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  56. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  57. i -= 8;
  58. RtlCopyMemory(&pjDst[i<<1], &pjDst[i], 8);
  59. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  60. i -= 8;
  61. // bytes 0-7 are already in place
  62. RtlCopyMemory(&pjDst[(i<<1)+8], &pjDst[i], 8);
  63. RtlCopyMemory(&pjDst[128], pjDst, 128);
  64. }
  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. * Warning: psoPattern will be null if the RB_DITHERCOLOR flag is set in
  82. * iHatch.
  83. *
  84. \**************************************************************************/
  85. BOOL DrvRealizeBrush(
  86. BRUSHOBJ* pbo,
  87. SURFOBJ* psoDst,
  88. SURFOBJ* psoPattern,
  89. SURFOBJ* psoMask,
  90. XLATEOBJ* pxlo,
  91. ULONG iHatch)
  92. {
  93. PDEV* ppdev;
  94. ULONG iPatternFormat;
  95. BYTE* pjSrc;
  96. BYTE* pjDst;
  97. LONG lSrcDelta;
  98. LONG cj;
  99. LONG dp;
  100. LONG i;
  101. LONG j;
  102. RBRUSH* prb;
  103. ULONG* pulXlate;
  104. ULONG cTile = 0;
  105. ULONG ulSize;
  106. ppdev = (PDEV*) psoDst->dhpdev;
  107. // We only handle brushes if we have an off-screen brush cache
  108. // available. If there isn't one, we can simply fail the realization,
  109. // and eventually GDI will do the drawing for us (although a lot
  110. // slower than we could have done it):
  111. if (!(ppdev->flStatus & STAT_BRUSH_CACHE))
  112. {
  113. DISPDBG((2,"There is no brush cache"));
  114. goto ReturnFalse;
  115. }
  116. if ((ppdev->ulChipID != W32P) && (ppdev->ulChipID != ET6000))
  117. {
  118. // Patterns are duplicated horizontally and vertically (4 tiles)
  119. cTile = 1;
  120. }
  121. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  122. ulSize = sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cBpp);
  123. if (cTile)
  124. {
  125. ulSize *= 4;
  126. }
  127. if (iHatch & RB_DITHERCOLOR)
  128. {
  129. // Implementing DITHERONREALIZE increased our score on a certain
  130. // unmentionable benchmark by 0.4 million 'megapixels'. Too bad
  131. // this didn't work in the first version of NT.
  132. prb = BRUSHOBJ_pvAllocRbrush(pbo, ulSize);
  133. if (prb == NULL)
  134. {
  135. goto ReturnFalse;
  136. }
  137. vRealizeDitherPattern(prb, iHatch, cTile);
  138. goto ReturnTrue;
  139. }
  140. // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  141. // support patterns of any other size, it's a safe bet that 99.9%
  142. // of the patterns we'll ever get will be 8x8:
  143. if ((psoPattern->sizlBitmap.cx != 8) ||
  144. (psoPattern->sizlBitmap.cy != 8))
  145. {
  146. goto ReturnFalse;
  147. }
  148. // At 8bpp, we handle patterns at 1bpp, 4bpp and 8bpp with/without an xlate.
  149. // At 16bpp, we handle patterns at 1bpp and 16bpp without an xlate.
  150. // At 32bpp, we handle patterns at 1bpp and 32bpp without an xlate.
  151. iPatternFormat = psoPattern->iBitmapFormat;
  152. if ((iPatternFormat == ppdev->iBitmapFormat) ||
  153. (iPatternFormat == BMF_1BPP) ||
  154. (iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  155. {
  156. cj = (8 * ppdev->cBpp); // Every pattern is 8 pels wide
  157. prb = BRUSHOBJ_pvAllocRbrush(pbo, ulSize);
  158. if (prb == NULL)
  159. {
  160. goto ReturnFalse;
  161. }
  162. // Initialize the fields we need:
  163. prb->ptlBrushOrg.x = LONG_MIN;
  164. prb->fl = 0;
  165. prb->pbe = NULL;
  166. lSrcDelta = psoPattern->lDelta;
  167. pjSrc = (BYTE*) psoPattern->pvScan0;
  168. pjDst = (BYTE*) &prb->aulPattern[0];
  169. if (ppdev->iBitmapFormat == iPatternFormat)
  170. {
  171. if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
  172. {
  173. DISPDBG((2, "Realizing un-translated brush"));
  174. // The pattern is the same color depth as the screen, and
  175. // there's no translation to be done:
  176. for (i = 8; i != 0; i--)
  177. {
  178. RtlCopyMemory(pjDst, pjSrc, cj);
  179. if (cTile)
  180. {
  181. RtlCopyMemory(pjDst + cj, pjDst, cj);
  182. pjDst += cj;
  183. }
  184. pjSrc += lSrcDelta;
  185. pjDst += cj;
  186. }
  187. }
  188. else if (ppdev->iBitmapFormat == BMF_8BPP)
  189. {
  190. DISPDBG((2, "Realizing 8bpp translated brush"));
  191. // The screen is 8bpp, and there's translation to be done:
  192. pulXlate = pxlo->pulXlate;
  193. for (i = 8; i != 0; i--)
  194. {
  195. for (j = 8; j != 0; j--)
  196. {
  197. *pjDst++ = (BYTE) pulXlate[*pjSrc++];
  198. }
  199. if (cTile)
  200. {
  201. RtlCopyMemory(pjDst, pjDst - 8, 8);
  202. pjDst += 8;
  203. }
  204. pjSrc += lSrcDelta - 8;
  205. }
  206. }
  207. else
  208. {
  209. // I don't feel like writing code to handle translations
  210. // when our screen is 16bpp or higher (although I probably
  211. // should; we could allocate a temporary buffer and use
  212. // GDI to convert, like is done in the VGA driver).
  213. DISPDBG((2, "Not realizing translated brush for 16bpp or higher"));
  214. goto ReturnFalse;
  215. }
  216. }
  217. else if (iPatternFormat == BMF_1BPP)
  218. {
  219. DISPDBG((2, "Realizing 1bpp brush"));
  220. pulXlate = pxlo->pulXlate;
  221. if (ppdev->iBitmapFormat == BMF_8BPP)
  222. {
  223. for (i = 8; i != 0; i--)
  224. {
  225. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 7) & 1];
  226. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 6) & 1];
  227. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 5) & 1];
  228. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 4) & 1];
  229. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 3) & 1];
  230. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 2) & 1];
  231. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 1) & 1];
  232. *pjDst++ = (BYTE) pulXlate[(*pjSrc >> 0) & 1];
  233. if (cTile)
  234. {
  235. RtlCopyMemory(pjDst, pjDst - cj, cj);
  236. pjDst += cj;
  237. }
  238. pjSrc += lSrcDelta;
  239. }
  240. }
  241. else if (ppdev->iBitmapFormat == BMF_16BPP)
  242. {
  243. dp = ppdev->cBpp; // Every pattern is 8 pels wide
  244. for (i = 8; i != 0; i--)
  245. {
  246. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 7) & 1]); pjDst += dp;
  247. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 6) & 1]); pjDst += dp;
  248. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 5) & 1]); pjDst += dp;
  249. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 4) & 1]); pjDst += dp;
  250. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 3) & 1]); pjDst += dp;
  251. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 2) & 1]); pjDst += dp;
  252. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 1) & 1]); pjDst += dp;
  253. *((WORD *)pjDst) = (WORD) (pulXlate[(*pjSrc >> 0) & 1]); pjDst += dp;
  254. if (cTile)
  255. {
  256. RtlCopyMemory(pjDst, pjDst - cj, cj);
  257. pjDst += cj;
  258. }
  259. pjSrc += lSrcDelta;
  260. }
  261. }
  262. else if (ppdev->iBitmapFormat == BMF_24BPP)
  263. {
  264. dp = ppdev->cBpp; // Every pattern is 8 pels wide
  265. for (i = 8; i != 0; i--)
  266. {
  267. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 7) & 1]; pjDst += dp;
  268. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 6) & 1]; pjDst += dp;
  269. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 5) & 1]; pjDst += dp;
  270. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 4) & 1]; pjDst += dp;
  271. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 3) & 1]; pjDst += dp;
  272. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 2) & 1]; pjDst += dp;
  273. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 1) & 1]; pjDst += dp;
  274. *((ULONG *)pjDst) = pulXlate[(*pjSrc >> 0) & 1]; pjDst += dp;
  275. if (cTile)
  276. {
  277. RtlCopyMemory(pjDst, pjDst - cj, cj);
  278. pjDst += cj;
  279. }
  280. pjSrc += lSrcDelta;
  281. }
  282. }
  283. }
  284. else
  285. {
  286. DISPDBG((2, "Realizing 4bpp brush"));
  287. // The screen is 8bpp and the pattern is 4bpp:
  288. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  289. (iPatternFormat == BMF_4BPP),
  290. "Messed up brush logic");
  291. pulXlate = pxlo->pulXlate;
  292. for (i = 8; i != 0; i--)
  293. {
  294. // Inner loop is repeated only 4 times because each loop
  295. // handles 2 pixels:
  296. for (j = 4; j != 0; j--)
  297. {
  298. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  299. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  300. pjSrc++;
  301. }
  302. if (cTile)
  303. {
  304. RtlCopyMemory(pjDst, pjDst - 8, 8);
  305. pjDst += 8;
  306. }
  307. pjSrc += lSrcDelta - 4;
  308. }
  309. }
  310. if (cTile)
  311. {
  312. pjDst = (BYTE*) &prb->aulPattern[0];
  313. RtlCopyMemory(pjDst + (cj*8*2), pjDst, cj*8*2);
  314. }
  315. ReturnTrue:
  316. ppdev->pfnFastPatRealize(ppdev, prb, NULL, FALSE);
  317. if (psoPattern != NULL)
  318. {
  319. DISPDBG((2, "Succeeded realization -- Type: %li Format: %li cx: %li cy: %li",
  320. psoPattern->iType, psoPattern->iBitmapFormat,
  321. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  322. }
  323. else
  324. {
  325. DISPDBG((2, "Succeeded realization -- it was a DITHER_ON_REALIZE"));
  326. }
  327. return(TRUE);
  328. }
  329. ReturnFalse:
  330. if (psoPattern != NULL)
  331. {
  332. DISPDBG((2, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  333. psoPattern->iType, psoPattern->iBitmapFormat,
  334. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  335. }
  336. return(FALSE);
  337. }
  338. /******************************Public*Routine******************************\
  339. * BOOL bEnableBrushCache
  340. *
  341. * Allocates off-screen memory for storing the brush cache.
  342. \**************************************************************************/
  343. BOOL bEnableBrushCache(
  344. PDEV* ppdev)
  345. {
  346. OH* poh; // Points to off-screen chunk of memory
  347. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  348. LONG i;
  349. pbe = &ppdev->abe[0]; // Points to where we'll put the first brush
  350. // cache entry
  351. {
  352. LONG x;
  353. LONG y;
  354. ULONG cTileFactor = 1;
  355. // Reserve the offscreen space that is required for the ACL to do
  356. // solid fills. If this fails, our solid fill code will not work.
  357. // We need two DWORD storage locations if we're going to do any
  358. // monochrome expansion stuff (font painting...).
  359. // Note: these must be dword aligned for the w32p
  360. // Not that *I* ever made this mistake, but don't
  361. // place any early outs (returns) before you allocate the solid
  362. // color work area. Not having a solid color work area is a
  363. // fatal error for this driver.
  364. DISPDBG((2,"Allocating solid brush work area"));
  365. poh = pohAllocate(ppdev, NULL, 8, 1, FLOH_MAKE_PERMANENT);
  366. ASSERTDD((poh != NULL),
  367. "We couldn't allocate offscreen space for the solid colors");
  368. if (!poh)
  369. return FALSE;
  370. ppdev->ulSolidColorOffset = (poh->y * ppdev->lDelta) + ppdev->cBpp * poh->x;
  371. DISPDBG((2,"Allocating brush cache"));
  372. if ((ppdev->ulChipID != W32P) && (ppdev->ulChipID != ET6000))
  373. {
  374. cTileFactor = 4;
  375. }
  376. //
  377. // Fix this mess up.
  378. //
  379. poh = pohAllocate(ppdev,
  380. NULL,
  381. cTileFactor * 2 * 64,
  382. FAST_BRUSH_COUNT,
  383. FLOH_MAKE_PERMANENT);
  384. if (poh == NULL)
  385. {
  386. DISPDBG((1,"Failed to allocate brush cache"));
  387. goto ReturnTrue; // See note about why we can return TRUE...
  388. }
  389. ppdev->cBrushCache = FAST_BRUSH_COUNT;
  390. // Hardware brushes require that the bits start on a 64 (height*width)
  391. // pixel boundary. The heap manager doesn't guarantee us any such
  392. // alignment, so we allocate a bit of extra room so that we can
  393. // do the alignment ourselves:
  394. x = poh->x;
  395. y = poh->y;
  396. for (i = FAST_BRUSH_COUNT; i != 0; i--)
  397. {
  398. ULONG ulOffset;
  399. ULONG ulCeil;
  400. ULONG ulDiff;
  401. // Note: I learned the HARD way that you can't just align x
  402. // to your pattern size, because the lDelta of your screen
  403. // is not guaranteed to be a multiple of your pattern size.
  404. // Since y is changing in this loop, the recalc must
  405. // be done inside this loop. I really need to set these
  406. // up with a hardcoded linear buffer or else make the
  407. // heap linear.
  408. ulOffset = (y * ppdev->lDelta) + (x * ppdev->cBpp);
  409. ulCeil = (ulOffset + ((ppdev->cBpp*64)-1)) & ~((ppdev->cBpp*64)-1);
  410. ulDiff = (ulCeil - ulOffset)/ppdev->cBpp;
  411. // If we hadn't allocated 'ppdev' with LMEM_ZEROINIT,
  412. // we would have to initialize pbe->prbVerify too...
  413. pbe->x = x + ulDiff;
  414. pbe->y = y;
  415. DISPDBG((2, "BrushCache[%d] pos(%d,%d) pbe(%d,%d) delta(%d) o(%d) c(%d) d(%d)",
  416. i,
  417. x,
  418. y,
  419. pbe->x,
  420. pbe->y,
  421. ppdev->lDelta,
  422. ulOffset,
  423. ulCeil,
  424. ulDiff
  425. ));
  426. //x += FAST_BRUSH_ALLOCATION * FAST_BRUSH_ALLOCATION; // size of a brush (x*y)
  427. y++;
  428. //
  429. pbe++;
  430. }
  431. }
  432. // Note that we don't have to remember 'poh' for when we have
  433. // to disable brushes -- the off-screen heap frees any
  434. // off-screen heap allocations automatically.
  435. // We successfully allocated the brush cache, so let's turn
  436. // on the switch showing that we can use it:
  437. ppdev->flStatus |= STAT_BRUSH_CACHE;
  438. ReturnTrue:
  439. // If we couldn't allocate a brush cache, it's not a catastrophic
  440. // failure; patterns will still work, although they'll be a bit
  441. // slower since they'll go through GDI. As a result we don't
  442. // actually have to fail this call:
  443. DISPDBG((5, "Passed bEnableBrushCache"));
  444. return(TRUE);
  445. }
  446. /******************************Public*Routine******************************\
  447. * VOID vDisableBrushCache
  448. *
  449. * Cleans up anything done in bEnableBrushCache.
  450. \**************************************************************************/
  451. VOID vDisableBrushCache(PDEV* ppdev)
  452. {
  453. // We ain't gotta do nothin'
  454. }
  455. /******************************Public*Routine******************************\
  456. * VOID vAssertModeBrushCache
  457. *
  458. * Resets the brush cache when we exit out of full-screen.
  459. \**************************************************************************/
  460. VOID vAssertModeBrushCache(
  461. PDEV* ppdev,
  462. BOOL bEnable)
  463. {
  464. BRUSHENTRY* pbe;
  465. LONG i;
  466. if (bEnable)
  467. {
  468. // Invalidate the brush cache:
  469. pbe = &ppdev->abe[0];
  470. for (i = ppdev->cBrushCache; i != 0; i--)
  471. {
  472. pbe->prbVerify = NULL;
  473. pbe++;
  474. }
  475. }
  476. }