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.

601 lines
18 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. #include "precomp.h"
  9. /******************************Public*Routine******************************\
  10. * VOID vRealizeDitherPattern
  11. *
  12. * Generates an 8x8 dither pattern, in our internal realization format, for
  13. * the colour ulRGBToDither. Note that the high byte of ulRGBToDither does
  14. * not need to be set to zero, because vComputeSubspaces ignores it.
  15. \**************************************************************************/
  16. VOID vRealizeDitherPattern(
  17. PDEV* ppdev,
  18. RBRUSH* prb,
  19. ULONG ulRGBToDither)
  20. {
  21. ULONG ulNumVertices;
  22. VERTEX_DATA vVertexData[4];
  23. VERTEX_DATA* pvVertexData;
  24. LONG i;
  25. // Calculate what colour subspaces are involved in the dither:
  26. pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData);
  27. // Now that we have found the bounding vertices and the number of
  28. // pixels to dither for each vertex, we can create the dither pattern
  29. ulNumVertices = (ULONG)(pvVertexData - vVertexData);
  30. // # of vertices with more than zero pixels in the dither
  31. // Do the actual dithering:
  32. vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices);
  33. // Initialize the fields we need:
  34. prb->fl = 0;
  35. prb->pfnFillPat = ppdev->pfnFillPatNative;
  36. for (i = 0; i < MAX_BOARDS; i++)
  37. {
  38. prb->apbe[i] = &ppdev->beUnrealizedBrush;
  39. }
  40. }
  41. /******************************Public*Routine******************************\
  42. * BOOL DrvRealizeBrush
  43. *
  44. * This function allows us to convert GDI brushes into an internal form
  45. * we can use. It may be called directly by GDI at SelectObject time, or
  46. * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
  47. * to create a realized brush in a function like DrvBitBlt.
  48. *
  49. * Note that we have no way of determining what the current Rop or brush
  50. * alignment are at this point.
  51. *
  52. \**************************************************************************/
  53. BOOL DrvRealizeBrush(
  54. BRUSHOBJ* pbo,
  55. SURFOBJ* psoDst,
  56. SURFOBJ* psoPattern,
  57. SURFOBJ* psoMask,
  58. XLATEOBJ* pxlo,
  59. ULONG iHatch)
  60. {
  61. PDEV* ppdev;
  62. ULONG iPatternFormat;
  63. BYTE jSrc;
  64. BYTE* pjSrc;
  65. BYTE* pjDst;
  66. LONG lSrcDelta;
  67. LONG cj;
  68. LONG i;
  69. LONG j;
  70. RBRUSH* prb;
  71. ULONG* pulXlate;
  72. SURFOBJ* psoPunt;
  73. RECTL rclDst;
  74. ppdev = (PDEV*) psoDst->dhpdev;
  75. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  76. if (iHatch & RB_DITHERCOLOR)
  77. {
  78. if (!(ppdev->flStatus & STAT_BRUSH_CACHE))
  79. goto ReturnFalse;
  80. // Implementing DITHERONREALIZE increased our score on a certain
  81. // unmentionable benchmark by 0.4 million 'megapixels'. Too bad
  82. // this didn't work in the first version of NT.
  83. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  84. sizeof(RBRUSH) + ppdev->ulBrushSize);
  85. if (prb == NULL)
  86. goto ReturnFalse;
  87. DISPDBG((5, "Realizing dithered brush"));
  88. vRealizeDitherPattern(ppdev, prb, iHatch);
  89. goto DoneWith8x8;
  90. }
  91. // We only handle colour brushes if we have an off-screen brush cache
  92. // available. If there isn't one, we can simply fail the realization,
  93. // and eventually GDI will do the drawing for us (although a lot
  94. // slower than we could have done it).
  95. //
  96. // We also only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  97. // support patterns of any other size, it's a safe bet that 99.9%
  98. // of the patterns we'll ever get will be 8x8:
  99. if ((psoPattern->sizlBitmap.cx != 8) ||
  100. (psoPattern->sizlBitmap.cy != 8) ||
  101. ((psoPattern->iBitmapFormat != BMF_1BPP) &&
  102. !(ppdev->flStatus & STAT_BRUSH_CACHE)))
  103. {
  104. goto ReturnFalse;
  105. }
  106. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  107. sizeof(RBRUSH) + ppdev->ulBrushSize);
  108. if (prb == NULL)
  109. {
  110. goto ReturnFalse;
  111. }
  112. // Initialize the fields we need:
  113. prb->fl = 0;
  114. prb->pfnFillPat = ppdev->pfnFillPatNative;
  115. for (i = 0; i < MAX_BOARDS; i++)
  116. {
  117. prb->apbe[i] = &ppdev->beUnrealizedBrush;
  118. }
  119. lSrcDelta = psoPattern->lDelta;
  120. pjSrc = (BYTE*) psoPattern->pvScan0;
  121. pjDst = (BYTE*) &prb->aulPattern[0];
  122. iPatternFormat = psoPattern->iBitmapFormat;
  123. if ((ppdev->iBitmapFormat == iPatternFormat) &&
  124. ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
  125. {
  126. DISPDBG((5, "Realizing un-translated brush"));
  127. // The pattern is the same colour depth as the screen, and
  128. // there's no translation to be done:
  129. cj = (8 * ppdev->cjPelSize); // Every pattern is 8 pels wide
  130. for (i = 8; i != 0; i--)
  131. {
  132. RtlCopyMemory(pjDst, pjSrc, cj);
  133. pjSrc += lSrcDelta;
  134. pjDst += cj;
  135. }
  136. }
  137. else if (iPatternFormat == BMF_1BPP)
  138. {
  139. if (ppdev->cjHwPel == 3)
  140. {
  141. // [!!!] - add true 24 bpp support
  142. goto ReturnFalse;
  143. }
  144. DISPDBG((5, "Realizing 1bpp brush"));
  145. // Since we allocated at least 64 bytes when we did our
  146. // BRUSHOBJ_pvAllocBrush call, we've got plenty of space
  147. // to store our monochrome brush.
  148. //
  149. // Since the Windows convention for monochrome bitmaps is that
  150. // the MSB of a given byte represents the leftmost pixel, which
  151. // is opposite that of the MGA, we must reverse the order of
  152. // each byte before using it in SRC0 through SRC3. Moreover,
  153. // each byte must be replicated so as to yield a 16x8 pattern.
  154. for (i = 8; i != 0; i--)
  155. {
  156. jSrc = gajFlip[*pjSrc];
  157. *(pjDst) = jSrc;
  158. *(pjDst + 1) = jSrc;
  159. pjDst += 2;
  160. pjSrc += lSrcDelta;
  161. }
  162. pulXlate = pxlo->pulXlate;
  163. prb->fl |= RBRUSH_2COLOR;
  164. prb->ulColor[1] = pulXlate[1];
  165. prb->ulColor[0] = pulXlate[0];
  166. prb->pfnFillPat = vFillPat1bpp;
  167. }
  168. else if ((iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  169. {
  170. DISPDBG((5, "Realizing 4bpp brush"));
  171. // The screen is 8bpp and the pattern is 4bpp:
  172. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  173. (iPatternFormat == BMF_4BPP),
  174. "Messed up brush logic");
  175. pulXlate = pxlo->pulXlate;
  176. for (i = 8; i != 0; i--)
  177. {
  178. // Inner loop is repeated only 4 times because each loop
  179. // handles 2 pixels:
  180. for (j = 4; j != 0; j--)
  181. {
  182. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  183. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  184. pjSrc++;
  185. }
  186. pjSrc += lSrcDelta - 4;
  187. }
  188. }
  189. else
  190. {
  191. // We've got a brush whose format we haven't special cased. No
  192. // problem, we can have GDI convert it to our device's format.
  193. // We simply use a temporary surface object that was created with
  194. // the same format as the display, and point it to our brush
  195. // realization:
  196. DISPDBG((5, "Realizing funky brush"));
  197. psoPunt = ppdev->psoPunt;
  198. psoPunt->pvScan0 = pjDst;
  199. psoPunt->lDelta = 8 * ppdev->cjPelSize;
  200. rclDst.left = 0;
  201. rclDst.top = 0;
  202. rclDst.right = 8;
  203. rclDst.bottom = 8;
  204. if (!EngCopyBits(psoPunt, psoPattern, NULL, pxlo,
  205. &rclDst, (POINTL*) &rclDst))
  206. {
  207. goto ReturnFalse;
  208. }
  209. }
  210. DoneWith8x8:
  211. if ((ppdev->ulBoardId == MGA_STORM) &&
  212. (ppdev->cjHwPel == 3) &&
  213. (iPatternFormat != BMF_1BPP))
  214. {
  215. // The display is at 24bpp, we need to build a special 16x8 brush.
  216. // We already have an 8x8 pattern.
  217. cj = 8 * 3;
  218. pjSrc = (BYTE*) &prb->aulPattern + (7 * cj);
  219. pjDst = (BYTE*) &prb->aulPattern + (7 * 2 * cj);
  220. for (i = 8; i != 0; i--)
  221. {
  222. RtlCopyMemory(pjDst, pjSrc, cj);
  223. pjDst += cj;
  224. RtlCopyMemory(pjDst, pjSrc, cj);
  225. pjSrc -= cj;
  226. pjDst -= (3 * cj);
  227. }
  228. }
  229. return(TRUE);
  230. ReturnFalse:
  231. if (psoPattern != NULL)
  232. {
  233. DISPDBG((5, "Failed realization -- Type: %li Format: %li cx: %li cy: %li flags: %x",
  234. psoPattern->iType, psoPattern->iBitmapFormat,
  235. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy, ppdev->flStatus));
  236. }
  237. return(FALSE);
  238. }
  239. /******************************Public*Routine******************************\
  240. * BOOL bMilEnableBrushCache
  241. *
  242. * Allocates off-screen memory for storing the brush cache.
  243. * Millenium (storm) specific.
  244. \**************************************************************************/
  245. BOOL bMilEnableBrushCache(
  246. PDEV* ppdev)
  247. {
  248. OH* poh; // Points to off-screen chunk of memory
  249. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  250. ULONG ulLinearStart;
  251. ULONG ulLinearEnd;
  252. LONG cBrushCache;
  253. ULONG ulTmp;
  254. LONG x;
  255. LONG y;
  256. LONG i;
  257. pbe = ppdev->pbe; // Points to where we'll put the first brush
  258. // cache entry
  259. poh = pohAllocate(ppdev,
  260. NULL,
  261. ppdev->cxMemory,
  262. BRUSH_CACHE_HEIGHT,
  263. FLOH_MAKE_PERMANENT);
  264. if (poh == NULL)
  265. {
  266. DISPDBG((2, "Brush cache NOT enabled"));
  267. goto ReturnTrue; // See note about why we can return TRUE...
  268. }
  269. ulLinearStart = (poh->y * ppdev->cxMemory) + ppdev->ulYDstOrg;
  270. ulLinearEnd = (poh->cy * ppdev->cxMemory) + ulLinearStart;
  271. // The brushes must be stored with a 256-pel alignment.
  272. ulLinearStart = (ulLinearStart + 0xff) & ~0xff;
  273. // In general, we'll be caching 8x8 brushes, so the number of cached
  274. // brushes can be four times the number of 256-pel slices that can be
  275. // stored from ulLinearStart to ulLinearEnd. In 24bpp, however, we'll
  276. // be caching 16x8 brushes, so we can cache only half this number.
  277. // Moreover, there are wrapping problems when a brush is stored in
  278. // the last slot of a 256-pel slice, so it's best not to use it.
  279. cBrushCache = (ulLinearEnd - ulLinearStart) >> 8;
  280. if (ppdev->cjPelSize == 3)
  281. {
  282. cBrushCache *= 2; // 24bpp, Don't forget they come in pairs...
  283. }
  284. else
  285. {
  286. cBrushCache *= 3; // ... or more, but beware of some slots!
  287. }
  288. pbe = EngAllocMem(FL_ZERO_MEMORY, cBrushCache * sizeof(BRUSHENTRY), ALLOC_TAG);
  289. if (pbe == NULL)
  290. goto ReturnTrue; // See note about why we can return TRUE...
  291. ppdev->cBrushCache = cBrushCache;
  292. ppdev->pbe = pbe;
  293. for (i = 0; i < cBrushCache; i++)
  294. {
  295. // If we hadn't allocated 'pbe' with FL_ZERO_MEMORY, we would have
  296. // to initialize pbe->prbVerify, too...
  297. // Set up linear coordinate for reading the pattern from offscreen
  298. // memory.
  299. pbe->ulLinear = ulLinearStart;
  300. // Set up coordinates for writing the pattern into offscreen
  301. // memory, assuming a HW_PATTERN_PITCH stride.
  302. ulTmp = ulLinearStart - ppdev->ulYDstOrg;
  303. x = ulTmp % ppdev->cxMemory;
  304. y = ulTmp / ppdev->cxMemory;
  305. pbe->ulLeft = x & 31;
  306. pbe->ulYDst = (y * ppdev->cxMemory + x) >> 5;
  307. pbe->pvScan0 = ppdev->pjScreen +
  308. ((ulTmp + ppdev->ulYDstOrg) * ppdev->cjPelSize);
  309. // Prepare for the next brush, accounting for the interleave.
  310. if (ppdev->cjHwPel == 3)
  311. {
  312. // At 24bpp, every second cached brush starts on a 256+16
  313. // boundary.
  314. if ((i & 1) == 0)
  315. {
  316. ulLinearStart += 16;
  317. }
  318. else
  319. {
  320. ulLinearStart += (256 - 16);
  321. }
  322. }
  323. else
  324. {
  325. // In general, we have three brushes in every 256-pel slice.
  326. if ((i % 3) == 2)
  327. {
  328. ulLinearStart += (256 - 16);
  329. }
  330. else
  331. {
  332. ulLinearStart += 8;
  333. }
  334. }
  335. pbe++;
  336. }
  337. // When we create a new brush, we always point it to our
  338. // 'beUnrealizedBrush' entry, which will always have 'prbVerify'
  339. // set to NULL. In this way, we can remove an 'if' from our
  340. // check to see if we have to realize the brush in 'vFillPat' --
  341. // we only have to compare to 'prbVerify'.
  342. ppdev->beUnrealizedBrush.prbVerify = NULL;
  343. // Note that we don't have to remember 'poh' for when we have
  344. // to disable brushes -- the off-screen heap frees any
  345. // off-screen heap allocations automatically.
  346. // We successfully allocated the brush cache, so let's turn
  347. // on the switch showing that we can use it.
  348. ppdev->flStatus |= STAT_BRUSH_CACHE;
  349. ReturnTrue:
  350. // If we couldn't allocate a brush cache, it's not a catastrophic
  351. // failure; patterns will still work, although they'll be a bit
  352. // slower since they'll go through GDI. As a result we don't
  353. // actually have to fail this call:
  354. DISPDBG((5, "Passed bMilEnableBrushCache"));
  355. return(TRUE);
  356. }
  357. /******************************Public*Routine******************************\
  358. * BOOL bEnableBrushCache
  359. *
  360. * Allocates off-screen memory for storing the brush cache.
  361. \**************************************************************************/
  362. BOOL bEnableBrushCache(
  363. PDEV* ppdev)
  364. {
  365. OH* poh; // Points to off-screen chunk of memory
  366. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  367. ULONG ulLinearStart;
  368. ULONG ulLinearEnd;
  369. LONG cBrushCache;
  370. ULONG ulTmp;
  371. LONG x;
  372. LONG y;
  373. LONG i;
  374. if (ppdev->ulBoardId == MGA_STORM)
  375. {
  376. return(bMilEnableBrushCache(ppdev));
  377. }
  378. pbe = ppdev->pbe; // Points to where we'll put the first brush
  379. // cache entry
  380. poh = pohAllocate(ppdev,
  381. NULL,
  382. ppdev->cxMemory,
  383. BRUSH_CACHE_HEIGHT,
  384. FLOH_MAKE_PERMANENT);
  385. if (poh == NULL)
  386. goto ReturnTrue; // See note about why we can return TRUE...
  387. ulLinearStart = (poh->y * ppdev->cxMemory) + ppdev->ulYDstOrg;
  388. ulLinearEnd = (BRUSH_CACHE_HEIGHT * ppdev->cxMemory) + ulLinearStart;
  389. // An MGA brush is always cached with a 256-pel alignment. The brush
  390. // can be 16x16, or two interleaved 16x8 brushes. We use the second
  391. // option, so that every second brush starts on a 256+16 alignment.
  392. //
  393. // So the brushes are stored in pairs, with a 256-pel alignment:
  394. ulLinearStart = (ulLinearStart + 0xff) & ~0xff;
  395. cBrushCache = (ulLinearEnd - ulLinearStart) >> 8;
  396. cBrushCache *= 2; // Don't forget they're pairs
  397. pbe = EngAllocMem(FL_ZERO_MEMORY,
  398. cBrushCache * sizeof(BRUSHENTRY), ALLOC_TAG);
  399. if (pbe == NULL)
  400. goto ReturnTrue; // See note about why we can return TRUE...
  401. ppdev->cBrushCache = cBrushCache;
  402. ppdev->pbe = pbe;
  403. do {
  404. // If we hadn't allocated 'pbe' with FL_ZERO_MEMORY, we would have
  405. // to initialize pbe->prbVerify, too...
  406. // Set up linear coordinate for reading the pattern from offscreen
  407. // memory:
  408. pbe->ulLinear = ulLinearStart;
  409. // Set up coordinates for writing the pattern into offscreen
  410. // memory, assuming a '32' stride:
  411. ulTmp = ulLinearStart - ppdev->ulYDstOrg;
  412. x = ulTmp % ppdev->cxMemory;
  413. y = ulTmp / ppdev->cxMemory;
  414. pbe->ulLeft = x & 31;
  415. pbe->ulYDst = (y * ppdev->cxMemory + x) >> 5;
  416. // Account for the interleave, where every second cached brush
  417. // starts on a 256+16 boundary:
  418. if ((cBrushCache & 1) == 0)
  419. {
  420. ulLinearStart += 16;
  421. }
  422. else
  423. {
  424. ulLinearStart += (256 - 16);
  425. }
  426. } while (pbe++, --cBrushCache != 0);
  427. // When we create a new brush, we always point it to our
  428. // 'beUnrealizedBrush' entry, which will always have 'prbVerify'
  429. // set to NULL. In this way, we can remove an 'if' from our
  430. // check to see if we have to realize the brush in 'vFillPat' --
  431. // we only have to compare to 'prbVerify':
  432. ppdev->beUnrealizedBrush.prbVerify = NULL;
  433. // Note that we don't have to remember 'poh' for when we have
  434. // to disable brushes -- the off-screen heap frees any
  435. // off-screen heap allocations automatically.
  436. // We successfully allocated the brush cache, so let's turn
  437. // on the switch showing that we can use it:
  438. ppdev->flStatus |= STAT_BRUSH_CACHE;
  439. ReturnTrue:
  440. // If we couldn't allocate a brush cache, it's not a catastrophic
  441. // failure; patterns will still work, although they'll be a bit
  442. // slower since they'll go through GDI. As a result we don't
  443. // actually have to fail this call:
  444. DISPDBG((5, "Passed bEnableBrushCache"));
  445. return(TRUE);
  446. }
  447. /******************************Public*Routine******************************\
  448. * VOID vDisableBrushCache
  449. *
  450. * Cleans up anything done in bEnableBrushCache.
  451. \**************************************************************************/
  452. VOID vDisableBrushCache(PDEV* ppdev)
  453. {
  454. EngFreeMem(ppdev->pbe);
  455. }
  456. /******************************Public*Routine******************************\
  457. * VOID vAssertModeBrushCache
  458. *
  459. * Resets the brush cache when we exit out of full-screen.
  460. \**************************************************************************/
  461. VOID vAssertModeBrushCache(
  462. PDEV* ppdev,
  463. BOOL bEnable)
  464. {
  465. BRUSHENTRY* pbe;
  466. LONG i;
  467. if (bEnable)
  468. {
  469. // Invalidate the brush cache:
  470. pbe = ppdev->pbe;
  471. for (i = ppdev->cBrushCache; i != 0; i--)
  472. {
  473. pbe->prbVerify = NULL;
  474. pbe++;
  475. }
  476. }
  477. }