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.

511 lines
16 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: Brush.c
  3. *
  4. * Handles all brush/pattern initialization and realization.
  5. *
  6. * Copyright (c) 1992-1995 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 colour 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. {
  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. for (i = 0; i < MAX_BOARDS; i++)
  36. {
  37. prb->apbe[i] = NULL;
  38. }
  39. }
  40. /******************************Public*Routine******************************\
  41. * BOOL DrvRealizeBrush
  42. *
  43. * This function allows us to convert GDI brushes into an internal form
  44. * we can use. It may be called directly by GDI at SelectObject time, or
  45. * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
  46. * to create a realized brush in a function like DrvBitBlt.
  47. *
  48. * Note that we have no way of determining what the current Rop or brush
  49. * alignment are at this point.
  50. *
  51. \**************************************************************************/
  52. BOOL DrvRealizeBrush(
  53. BRUSHOBJ* pbo,
  54. SURFOBJ* psoDst,
  55. SURFOBJ* psoPattern,
  56. SURFOBJ* psoMask,
  57. XLATEOBJ* pxlo,
  58. ULONG iHatch)
  59. {
  60. PDEV* ppdev;
  61. ULONG iPatternFormat;
  62. BYTE* pjSrc;
  63. BYTE* pjDst;
  64. BYTE jSrc;
  65. LONG lSrcDelta;
  66. LONG cj;
  67. LONG i;
  68. LONG j;
  69. RBRUSH* prb;
  70. ULONG* pulXlate;
  71. ULONG ulColor;
  72. ppdev = (PDEV*) psoDst->dhpdev;
  73. // We don't do brushes in high-colour modes on the P9000:
  74. if (ppdev->flStat & STAT_UNACCELERATED)
  75. goto ReturnFalse;
  76. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  77. if (iHatch & RB_DITHERCOLOR)
  78. {
  79. // Implementing DITHERONREALIZE increased our score on a certain
  80. // unmentionable benchmark by 0.4 million 'megapixels'. Too bad
  81. // this didn't work in the first version of NT.
  82. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  83. sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cjPel));
  84. if (prb == NULL)
  85. goto ReturnFalse;
  86. if (!P9000(ppdev))
  87. {
  88. ASSERTDD(ppdev->iBitmapFormat == BMF_8BPP,
  89. "GCAPS_COLOR_DITHER shouldn't be set at higher than 8bpp");
  90. // Oh goody, we get to use the P9100's 4-colour pattern
  91. // support:
  92. vRealize4ColorDither(prb, iHatch);
  93. goto ReturnTrue;
  94. }
  95. else
  96. {
  97. // We do coloured patterns on the P9000 only at 8bpp, and only
  98. // if we've successfully managed to allocate an off-screen
  99. // brush cache:
  100. if (!(ppdev->flStat & STAT_BRUSH_CACHE))
  101. goto ReturnFalse;
  102. vRealizeDitherPattern(prb, iHatch);
  103. goto ReturnTrue;
  104. }
  105. }
  106. // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  107. // support patterns of any other size, it's a safe bet that 99.9%
  108. // of the patterns we'll ever get will be 8x8:
  109. if ((psoPattern->sizlBitmap.cx != 8) ||
  110. (psoPattern->sizlBitmap.cy != 8))
  111. goto ReturnFalse;
  112. // At 8bpp, we handle patterns at 1bpp, 4bpp and 8bpp with/without an xlate.
  113. // At 16bpp, we handle patterns at 1bpp on the P9100.
  114. // At 32bpp, we handle patterns at 1bpp on the P9100.
  115. iPatternFormat = psoPattern->iBitmapFormat;
  116. // We only handle arbitrary color brushes if we have an off-screen
  117. // brush cache available.
  118. if ((iPatternFormat != BMF_1BPP) && !(ppdev->flStat & STAT_BRUSH_CACHE))
  119. goto ReturnFalse;
  120. if ((iPatternFormat == BMF_1BPP) ||
  121. (iPatternFormat == ppdev->iBitmapFormat) ||
  122. (iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  123. {
  124. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  125. sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cjPel));
  126. if (prb == NULL)
  127. goto ReturnFalse;
  128. // Initialize the fields we need:
  129. prb->fl = 0;
  130. for (i = 0; i < MAX_BOARDS; i++)
  131. {
  132. prb->apbe[i] = NULL;
  133. }
  134. lSrcDelta = psoPattern->lDelta;
  135. pjSrc = (BYTE*) psoPattern->pvScan0;
  136. pjDst = (BYTE*) &prb->aulPattern[0];
  137. if (ppdev->iBitmapFormat == iPatternFormat)
  138. {
  139. if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
  140. {
  141. DISPDBG((1, "Realizing un-translated brush"));
  142. // The pattern is the same colour depth as the screen, and
  143. // there's no translation to be done:
  144. cj = (8 * ppdev->cjPel); // Every pattern is 8 pels wide
  145. for (i = 8; i != 0; i--)
  146. {
  147. RtlCopyMemory(pjDst, pjSrc, cj);
  148. pjSrc += lSrcDelta;
  149. pjDst += cj;
  150. }
  151. }
  152. else if (ppdev->iBitmapFormat == BMF_8BPP)
  153. {
  154. DISPDBG((1, "Realizing 8bpp translated brush"));
  155. // The screen is 8bpp, and there's translation to be done:
  156. pulXlate = pxlo->pulXlate;
  157. for (i = 8; i != 0; i--)
  158. {
  159. for (j = 8; j != 0; j--)
  160. {
  161. *pjDst++ = (BYTE) pulXlate[*pjSrc++];
  162. }
  163. pjSrc += lSrcDelta - 8;
  164. }
  165. }
  166. else
  167. {
  168. // I don't feel like writing code to handle translations
  169. // when our screen is 16bpp or higher (although I probably
  170. // should; we could allocate a temporary buffer and use
  171. // GDI to convert, like is done in the VGA driver).
  172. goto ReturnFalse;
  173. }
  174. }
  175. else if (iPatternFormat == BMF_1BPP)
  176. {
  177. DISPDBG((1, "Realizing 1bpp brush"));
  178. // We word align the monochrome bitmap so that every row starts
  179. // on a new word (so that we can do word writes later to transfer
  180. // the bitmap):
  181. for (i = 4; i != 0; i--)
  182. {
  183. // The P9000 uses a monochrome 16x16 pattern, but we're
  184. // given an 8x8 source pattern. So copy each source row
  185. // horizontally.
  186. //
  187. // This works for the P9100 too, because although it supports
  188. // only an 8x8 monochrome pattern, it ignores the high byte
  189. // in every word.
  190. jSrc = *pjSrc;
  191. pjSrc += lSrcDelta;
  192. // The pattern register we use has little-endian byte ordering:
  193. *(pjDst ) = jSrc;
  194. *(pjDst + 1) = jSrc;
  195. jSrc = *pjSrc;
  196. pjSrc += lSrcDelta;
  197. *(pjDst + 2) = jSrc;
  198. *(pjDst + 3) = jSrc;
  199. pjDst += 4;
  200. }
  201. pulXlate = pxlo->pulXlate;
  202. prb->fl = RBRUSH_2COLOR;
  203. // The P9100 require that colours be 'packed' into a dword.
  204. // We do it here rather than when we go to draw because
  205. // we may draw using the same brush multiple times...
  206. PACK_COLOR(ppdev, pulXlate[0], ulColor);
  207. prb->ulColor[0] = ulColor;
  208. PACK_COLOR(ppdev, pulXlate[1], ulColor);
  209. prb->ulColor[1] = ulColor;
  210. }
  211. else
  212. {
  213. DISPDBG((1, "Realizing 4bpp brush"));
  214. // The screen is 8bpp and the pattern is 4bpp:
  215. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  216. (iPatternFormat == BMF_4BPP),
  217. "Messed up brush logic");
  218. pulXlate = pxlo->pulXlate;
  219. for (i = 8; i != 0; i--)
  220. {
  221. // Inner loop is repeated only 4 times because each loop
  222. // handles 2 pixels:
  223. for (j = 4; j != 0; j--)
  224. {
  225. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  226. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  227. pjSrc++;
  228. }
  229. pjSrc += lSrcDelta - 4;
  230. }
  231. }
  232. ReturnTrue:
  233. // The last time I checked, GDI took some 500 odd instructions to
  234. // get from here back to whereever we called 'BRUSHOBJ_pvGetRbrush'.
  235. // We can at least use this time to get some overlap between the
  236. // CPU and the display hardware: we'll initialize the 72x72 off-
  237. // screen cache entry now, which will keep the accelerator busy for
  238. // a while.
  239. if (!prb->fl & (RBRUSH_2COLOR | RBRUSH_4COLOR))
  240. {
  241. ASSERTDD(ppdev->bEnabled, "Realizing brush when in full-screen?");
  242. vSlowPatRealize(ppdev, prb);
  243. }
  244. return(TRUE);
  245. }
  246. ReturnFalse:
  247. if (psoPattern != NULL)
  248. {
  249. DISPDBG((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  250. psoPattern->iType, psoPattern->iBitmapFormat,
  251. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  252. }
  253. return(FALSE);
  254. }
  255. /******************************Public*Routine******************************\
  256. * VOID vAssertModeBrushCache
  257. *
  258. * Resets the brush cache when we exit out of full-screen.
  259. \**************************************************************************/
  260. VOID vAssertModeBrushCache(
  261. PDEV* ppdev,
  262. BOOL bEnable)
  263. {
  264. BRUSHENTRY* pbe;
  265. CIRCLEENTRY* pce;
  266. LONG i;
  267. BYTE* pjBase;
  268. if (bEnable)
  269. {
  270. // Invalidate the brush cache:
  271. pbe = &ppdev->abe[0];
  272. for (i = ppdev->cBrushCache; i != 0; i--)
  273. {
  274. pbe->prbVerify = NULL;
  275. pbe++;
  276. }
  277. // Invalidate the circle cache:
  278. pce = &ppdev->ace[0];
  279. for (i = TOTAL_CIRCLE_COUNT; i != 0; i--)
  280. {
  281. pce->rcfxCircle.xLeft = 0;
  282. pce->rcfxCircle.xRight = 0;
  283. pce++;
  284. }
  285. // Download our favourite pattern for doing solid fills when
  286. // running 16bpp on the P9000:
  287. if ((ppdev->flStat & STAT_UNACCELERATED) &&
  288. (ppdev->iBitmapFormat == BMF_16BPP))
  289. {
  290. pjBase = ppdev->pjBase;
  291. CP_WAIT(ppdev, pjBase);
  292. for (i = 0; i < 8; i++)
  293. {
  294. CP_PATTERN(ppdev, pjBase, i, 0xAAAAAAAA);
  295. }
  296. // Anchor the pattern origin, too:
  297. CP_PATTERN_ORGX(ppdev, pjBase, 0);
  298. CP_PATTERN_ORGY(ppdev, pjBase, 0);
  299. }
  300. }
  301. }
  302. /******************************Public*Routine******************************\
  303. * BOOL bEnableBrushCache
  304. *
  305. * Allocates off-screen memory for storing the brush cache.
  306. \**************************************************************************/
  307. BOOL bEnableBrushCache(
  308. PDEV* ppdev)
  309. {
  310. OH* poh; // Points to off-screen chunk of memory
  311. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  312. LONG i;
  313. LONG j;
  314. CIRCLEENTRY* pce;
  315. // On the P9000, we draw coloured patterns using screen-to-screen
  316. // copies. When a coloured pattern is used, we first expand the
  317. // 8 x 8 pattern to a 64 x 64 pattern in off-screen memory; we
  318. // then use this as the basis for our screen-to-screen blts to the
  319. // target rectangle. The off-screen 64 x 64 pattern is cached for
  320. // future use.
  321. //
  322. // Coloured patterns are used primarily at 8bpp, for dithers. The
  323. // P9100 has direct support for 4-coloured patterns at 8bpp, which
  324. // allows it to to draw any dithered colours using the hardware
  325. // (our dithers are always a maximum of 4 colours). Consequently,
  326. // we only use the off-screen brush cache on the P9000, and only
  327. // at 8bpp.
  328. if (P9000(ppdev) && (ppdev->flStat & STAT_8BPP))
  329. {
  330. // Typically, we'll be running at 1024x768x256 on a 1meg board,
  331. // giving us off-screen memory of the dimension 1024x253 (accounting
  332. // for the space taken by the hardware pointer). If we allocate
  333. // the brush cache as one long one-high row of brushes, the heap
  334. // manager would shave that amount off the largest chunk of memory
  335. // we could allocate (meaning the largest bitmap potentially stored
  336. // in off-screen memory couldn't be larger than 253 - 64 = 189 pels
  337. // high, but it could be 1024 wide).
  338. //
  339. // To make this more square, I want to shave off a left-side chunk
  340. // for the brush cache, and I want at least 8 brushes cached.
  341. // Since floor(253/64) = 3, we'll allocate a 3 x 3 cache:
  342. poh = pohAllocatePermanent(ppdev,
  343. SLOW_BRUSH_CACHE_DIM * SLOW_BRUSH_ALLOCATION,
  344. SLOW_BRUSH_CACHE_DIM * SLOW_BRUSH_ALLOCATION);
  345. if (poh == NULL)
  346. goto ReturnTrue; // See note about why we can return TRUE...
  347. ppdev->cBrushCache = SLOW_BRUSH_COUNT;
  348. pbe = &ppdev->abe[0]; // Points to where we'll put the first brush
  349. // cache entry
  350. for (i = 0; i < SLOW_BRUSH_CACHE_DIM; i++)
  351. {
  352. for (j = 0; j < SLOW_BRUSH_CACHE_DIM; j++)
  353. {
  354. pbe->x = poh->x + (i * SLOW_BRUSH_ALLOCATION);
  355. pbe->y = poh->y + (j * SLOW_BRUSH_ALLOCATION);
  356. pbe++;
  357. }
  358. }
  359. // Note that we don't have to remember 'poh' for when we have
  360. // to disable brushes -- the off-screen heap frees any
  361. // off-screen heap allocations automatically.
  362. // We successfully allocated the brush cache, so let's turn
  363. // on the switch showing that we can use it:
  364. ppdev->flStat |= STAT_BRUSH_CACHE;
  365. }
  366. // Now allocate our circle cache.
  367. //
  368. // Note that we don't have to initially mark the entries as invalid,
  369. // as the ppdev was zero-filled, and so we are assured that every
  370. // 'rcfxBound' will be {0, 0, 0, 0}, which will never match any
  371. // circle when looking for a matching entry.
  372. poh = pohAllocatePermanent(ppdev, CIRCLE_ALLOCATION_CX * TOTAL_CIRCLE_COUNT,
  373. CIRCLE_ALLOCATION_CY);
  374. if (poh == NULL)
  375. goto ReturnTrue;
  376. pce = &ppdev->ace[0]; // Points to where we'll put the first circle
  377. // cache entry
  378. for (i = 0; i < TOTAL_CIRCLE_COUNT; i++)
  379. {
  380. pce->x = poh->x + (i * CIRCLE_ALLOCATION_CX);
  381. pce->y = poh->y;
  382. pce++;
  383. }
  384. ppdev->flStat |= STAT_CIRCLE_CACHE;
  385. ReturnTrue:
  386. // Invalidate our caches and initialize our high-colour pattern:
  387. vAssertModeBrushCache(ppdev, TRUE);
  388. // If we couldn't allocate a brush cache, it's not a catastrophic
  389. // failure; patterns will still work, although they'll be a bit
  390. // slower since they'll go through GDI. As a result we don't
  391. // actually have to fail this call:
  392. DISPDBG((5, "Passed bEnableBrushCache"));
  393. return(TRUE);
  394. }
  395. /******************************Public*Routine******************************\
  396. * VOID vDisableBrushCache
  397. *
  398. * Cleans up anything done in bEnableBrushCache.
  399. \**************************************************************************/
  400. VOID vDisableBrushCache(PDEV* ppdev)
  401. {
  402. // We ain't gotta do nothin'
  403. }