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.

438 lines
14 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: Brush.c
  3. *
  4. * Handles all brush/pattern initialization and realization.
  5. *
  6. * Copyright (c) 1992-1994 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. // Calculate what colour subspaces are involved in the dither:
  25. pvVertexData = vComputeSubspaces(ulRGBToDither, vVertexData);
  26. // Now that we have found the bounding vertices and the number of
  27. // pixels to dither for each vertex, we can create the dither pattern
  28. ulNumVertices = pvVertexData - vVertexData;
  29. // # of vertices with more than zero pixels in the dither
  30. // Do the actual dithering:
  31. vDitherColor(&prb->aulPattern[0], vVertexData, pvVertexData, ulNumVertices);
  32. prb->fl = 0;
  33. prb->ptlBrushOrg.x = -1;
  34. prb->pbe = NULL; // Initialize the fields we need
  35. }
  36. /******************************Public*Routine******************************\
  37. * BOOL DrvRealizeBrush
  38. *
  39. * This function allows us to convert GDI brushes into an internal form
  40. * we can use. It is called by GDI when we've called BRUSHOBJ_pvGetRbrush
  41. * in some other function like DrvBitBlt, and GDI doesn't happen have a cached
  42. * realization lying around.
  43. *
  44. * Input:
  45. *
  46. * ppdev->bRealizeTransparent -- Hint for whether or not the brush should be
  47. * realized for transparency. If this hint is
  48. * wrong, there will be no error, but the brush
  49. * will have to be unnecessarily re-realized.
  50. *
  51. * Note: You should always set 'ppdev->bRealizeTransparent' before calling
  52. * BRUSHOBJ_pvGetRbrush!
  53. *
  54. \**************************************************************************/
  55. BOOL DrvRealizeBrush(
  56. BRUSHOBJ* pbo,
  57. SURFOBJ* psoDst,
  58. SURFOBJ* psoPattern,
  59. SURFOBJ* psoMask,
  60. XLATEOBJ* pxlo,
  61. ULONG iHatch)
  62. {
  63. PDEV* ppdev;
  64. ULONG iPatternFormat;
  65. BYTE* pjSrc;
  66. BYTE* pjDst;
  67. LONG lSrcDelta;
  68. LONG cj;
  69. LONG i;
  70. LONG j;
  71. RBRUSH* prb;
  72. ULONG* pulXlate;
  73. ppdev = (PDEV*) psoDst->dhpdev;
  74. // We only handle brushes if we have an off-screen brush cache
  75. // available. If there isn't one, we can simply fail the realization,
  76. // and eventually GDI will do the drawing for us (although a lot
  77. // slower than we could have done it):
  78. if (!(ppdev->flStatus & STAT_BRUSH_CACHE))
  79. goto ReturnFalse;
  80. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  81. if (iHatch & RB_DITHERCOLOR)
  82. {
  83. // Implementing DITHERONREALIZE increased our score on a certain
  84. // unmentionable benchmark by 0.4 million 'megapixels'. Too bad
  85. // this didn't work in the first version of NT.
  86. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  87. sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
  88. if (prb == NULL)
  89. goto ReturnFalse;
  90. vRealizeDitherPattern(prb, iHatch);
  91. goto ReturnTrue;
  92. }
  93. // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  94. // support patterns of any other size, it's a safe bet that 99.9%
  95. // of the patterns we'll ever get will be 8x8:
  96. if ((psoPattern->sizlBitmap.cx != 8) ||
  97. (psoPattern->sizlBitmap.cy != 8))
  98. goto ReturnFalse;
  99. // At 8bpp, we handle patterns at 1bpp, 4bpp and 8bpp with/without an xlate.
  100. // At 16bpp, we handle patterns at 1bpp and 16bpp without an xlate.
  101. // At 32bpp, we handle patterns at 1bpp and 32bpp without an xlate.
  102. iPatternFormat = psoPattern->iBitmapFormat;
  103. if ((iPatternFormat == BMF_1BPP) ||
  104. (iPatternFormat == ppdev->iBitmapFormat) ||
  105. (iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  106. {
  107. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  108. sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
  109. if (prb == NULL)
  110. goto ReturnFalse;
  111. prb->fl = 0;
  112. prb->ptlBrushOrg.x = -1;
  113. prb->pbe = NULL; // Initialize the fields we need
  114. lSrcDelta = psoPattern->lDelta;
  115. pjSrc = (BYTE*) psoPattern->pvScan0;
  116. pjDst = (BYTE*) &prb->aulPattern[0];
  117. if (ppdev->iBitmapFormat == iPatternFormat)
  118. {
  119. if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL))
  120. {
  121. DISPDBG((1, "Realizing un-translated brush"));
  122. // The pattern is the same colour depth as the screen, and
  123. // there's no translation to be done:
  124. cj = (8 << ppdev->cPelSize); // Every pattern is 8 pels wide
  125. for (i = 8; i != 0; i--)
  126. {
  127. RtlCopyMemory(pjDst, pjSrc, cj);
  128. pjSrc += lSrcDelta;
  129. pjDst += cj;
  130. }
  131. }
  132. else if (ppdev->iBitmapFormat == BMF_8BPP)
  133. {
  134. DISPDBG((1, "Realizing 8bpp translated brush"));
  135. // The screen is 8bpp, and there's translation to be done:
  136. pulXlate = pxlo->pulXlate;
  137. for (i = 8; i != 0; i--)
  138. {
  139. for (j = 8; j != 0; j--)
  140. {
  141. *pjDst++ = (BYTE) pulXlate[*pjSrc++];
  142. }
  143. pjSrc += lSrcDelta - 8;
  144. }
  145. }
  146. else
  147. {
  148. // I don't feel like writing code to handle translations
  149. // when our screen is 16bpp or higher (although I probably
  150. // should; we could allocate a temporary buffer and use
  151. // GDI to convert, like is done in the VGA driver).
  152. goto ReturnFalse;
  153. }
  154. }
  155. else if (iPatternFormat == BMF_1BPP)
  156. {
  157. DISPDBG((1, "Realizing 1bpp brush"));
  158. // We word align the monochrome bitmap so that every row starts
  159. // on a new word (so that we can do word writes later to transfer
  160. // the bitmap):
  161. for (i = 8; i != 0; i--)
  162. {
  163. *pjDst = *pjSrc;
  164. pjDst += sizeof(WORD);
  165. pjSrc += lSrcDelta;
  166. }
  167. pulXlate = pxlo->pulXlate;
  168. prb->fl |= RBRUSH_2COLOR;
  169. prb->ulForeColor = pulXlate[1];
  170. prb->ulBackColor = pulXlate[0];
  171. }
  172. else
  173. {
  174. DISPDBG((1, "Realizing 4bpp brush"));
  175. // The screen is 8bpp and the pattern is 4bpp:
  176. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  177. (iPatternFormat == BMF_4BPP),
  178. "Messed up brush logic");
  179. pulXlate = pxlo->pulXlate;
  180. for (i = 8; i != 0; i--)
  181. {
  182. // Inner loop is repeated only 4 times because each loop
  183. // handles 2 pixels:
  184. for (j = 4; j != 0; j--)
  185. {
  186. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  187. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  188. pjSrc++;
  189. }
  190. pjSrc += lSrcDelta - 4;
  191. }
  192. }
  193. ReturnTrue:
  194. #if SLOWFILL_PATTERNS
  195. {
  196. #if FASTFILL_PATTERNS
  197. if (!(ppdev->flCaps & CAPS_HW_PATTERNS))
  198. #endif
  199. {
  200. // The last time I checked, GDI took some 500 odd instructions to
  201. // get from here back to whereever we called 'BRUSHOBJ_pvGetRbrush'.
  202. // We can at least use this time to get some overlap between the
  203. // CPU and the display hardware: we'll initialize the 72x72 off-
  204. // screen cache entry now, which will keep the accelerator busy for
  205. // a while.
  206. //
  207. // We don't do this if we have hardware patterns because:
  208. //
  209. // a) S3 hardware patterns require that the off-screen cached
  210. // brush be correctly aligned, and at this point we don't have
  211. // access to the 'pptlBrush' brush origin (although we could
  212. // have copied it into the PDEV before calling
  213. // BRUSHOBJ_pvGetRbrush).
  214. //
  215. // b) S3 hardware patterns require only an 8x8 copy of the
  216. // pattern; it is not expanded to 72x72, so there isn't even
  217. // any opportunity for CPU/accelerator processing overlap.
  218. vIoSlowPatRealize(ppdev, prb, ppdev->bRealizeTransparent);
  219. }
  220. }
  221. #endif
  222. return(TRUE);
  223. }
  224. ReturnFalse:
  225. if (psoPattern != NULL)
  226. {
  227. DISPDBG((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  228. psoPattern->iType, psoPattern->iBitmapFormat,
  229. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  230. }
  231. return(FALSE);
  232. }
  233. /******************************Public*Routine******************************\
  234. * BOOL bEnableBrushCache
  235. *
  236. * Allocates off-screen memory for storing the brush cache.
  237. \**************************************************************************/
  238. BOOL bEnableBrushCache(
  239. PDEV* ppdev)
  240. {
  241. OH* poh; // Points to off-screen chunk of memory
  242. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  243. LONG i;
  244. pbe = &ppdev->abe[0]; // Points to where we'll put the first brush
  245. // cache entry
  246. #if FASTFILL_PATTERNS
  247. if (ppdev->flCaps & CAPS_HW_PATTERNS)
  248. {
  249. LONG x;
  250. LONG y;
  251. poh = pohAllocatePermanent(ppdev,
  252. (FAST_BRUSH_COUNT + 1) * FAST_BRUSH_ALLOCATION,
  253. FAST_BRUSH_ALLOCATION);
  254. if (poh == NULL)
  255. goto ReturnTrue; // See note about why we can return TRUE...
  256. ppdev->cBrushCache = FAST_BRUSH_COUNT;
  257. // Hardware brushes require that the x-coordinate start on an 8
  258. // pixel boundary. The heap manager doesn't guarantee us any such
  259. // alignment, so we allocate a bit of extra room so that we can
  260. // do the alignment ourselves:
  261. x = (poh->x + 7) & ~7L;
  262. y = poh->y;
  263. for (i = FAST_BRUSH_COUNT; i != 0; i--)
  264. {
  265. // If we hadn't allocated 'ppdev' with LMEM_ZEROINIT,
  266. // we would have to initialize pbe->prbVerify too...
  267. pbe->x = x;
  268. pbe->y = y;
  269. x += FAST_BRUSH_ALLOCATION;
  270. pbe++;
  271. }
  272. }
  273. #endif
  274. #if SLOWFILL_PATTERNS && FASTFILL_PATTERNS
  275. else
  276. #endif
  277. #if SLOWFILL_PATTERNS
  278. {
  279. LONG j;
  280. ppdev->pfnFillPat = vIoFillPatSlow; // Override FillPatFast
  281. // Typically, we'll be running at 1024x768x256 on a 1meg board,
  282. // giving us off-screen memory of the dimension 1024x253 (accounting
  283. // for the space taken by the hardware pointer). If we allocate
  284. // the brush cache as one long one-high row of brushes, the heap
  285. // manager would shave that amount off the largest chunk of memory
  286. // we could allocate (meaning the largest bitmap potentially stored
  287. // in off-screen memory couldn't be larger than 253 - 64 = 189 pels
  288. // high, but it could be 1024 wide).
  289. //
  290. // To make this more square, I want to shave off a left-side chunk
  291. // for the brush cache, and I want at least 8 brushes cached.
  292. // Since floor(253/64) = 3, we'll allocate a 3 x 3 cache:
  293. poh = pohAllocatePermanent(ppdev,
  294. SLOW_BRUSH_CACHE_DIM * SLOW_BRUSH_ALLOCATION,
  295. SLOW_BRUSH_CACHE_DIM * SLOW_BRUSH_ALLOCATION);
  296. if (poh == NULL)
  297. goto ReturnTrue; // See note about why we can return TRUE...
  298. ppdev->cBrushCache = SLOW_BRUSH_COUNT;
  299. for (i = 0; i < SLOW_BRUSH_CACHE_DIM; i++)
  300. {
  301. for (j = 0; j < SLOW_BRUSH_CACHE_DIM; j++)
  302. {
  303. pbe->x = poh->x + (i * SLOW_BRUSH_ALLOCATION);
  304. pbe->y = poh->y + (j * SLOW_BRUSH_ALLOCATION);
  305. pbe++;
  306. }
  307. }
  308. }
  309. #endif // SLOWFILL_PATTERNS
  310. // Note that we don't have to remember 'poh' for when we have
  311. // to disable brushes -- the off-screen heap frees any
  312. // off-screen heap allocations automatically.
  313. // We successfully allocated the brush cache, so let's turn
  314. // on the switch showing that we can use it:
  315. ppdev->flStatus |= STAT_BRUSH_CACHE;
  316. ReturnTrue:
  317. // If we couldn't allocate a brush cache, it's not a catastrophic
  318. // failure; patterns will still work, although they'll be a bit
  319. // slower since they'll go through GDI. As a result we don't
  320. // actually have to fail this call:
  321. DISPDBG((5, "Passed bEnableBrushCache"));
  322. return(TRUE);
  323. }
  324. /******************************Public*Routine******************************\
  325. * VOID vDisableBrushCache
  326. *
  327. * Cleans up anything done in bEnableBrushCache.
  328. \**************************************************************************/
  329. VOID vDisableBrushCache(PDEV* ppdev)
  330. {
  331. // We ain't gotta do nothin'
  332. }
  333. /******************************Public*Routine******************************\
  334. * VOID vAssertModeBrushCache
  335. *
  336. * Resets the brush cache when we exit out of full-screen.
  337. \**************************************************************************/
  338. VOID vAssertModeBrushCache(
  339. PDEV* ppdev,
  340. BOOL bEnable)
  341. {
  342. BRUSHENTRY* pbe;
  343. LONG i;
  344. if (bEnable)
  345. {
  346. // Invalidate the brush cache:
  347. pbe = &ppdev->abe[0];
  348. for (i = ppdev->cBrushCache; i != 0; i--)
  349. {
  350. pbe->prbVerify = NULL;
  351. pbe++;
  352. }
  353. }
  354. }