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.

397 lines
12 KiB

  1. /******************************Module*Header*******************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: Brush.c
  8. *
  9. * Handles all brush/pattern initialization and realization.
  10. *
  11. * Copyright (c) 1992-1998 Microsoft Corporation
  12. *
  13. \**************************************************************************/
  14. #include "precomp.h"
  15. /******************************Public*Routine******************************\
  16. * VOID vRealizeDitherPattern
  17. *
  18. * Generates an 8x8 dither pattern, in our internal realization format, for
  19. * the colour ulRGBToDither. Note that the high byte of ulRGBToDither does
  20. * not need to be set to zero, because EngDitherColor ignores it.
  21. \**************************************************************************/
  22. VOID vRealizeDitherPattern(
  23. HDEV hdev,
  24. RBRUSH* prb,
  25. ULONG ulRGBToDither)
  26. {
  27. // Do the actual dithering:
  28. EngDitherColor(hdev, DM_DEFAULT, ulRGBToDither, &prb->aulPattern[0]);
  29. // Initialize the fields we need:
  30. prb->ptlBrushOrg.x = LONG_MIN;
  31. prb->fl = 0;
  32. prb->pbe = NULL;
  33. }
  34. /******************************Public*Routine******************************\
  35. * BOOL DrvRealizeBrush
  36. *
  37. * This function allows us to convert GDI brushes into an internal form
  38. * we can use. It may be called directly by GDI at SelectObject time, or
  39. * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
  40. * to create a realized brush in a function like DrvBitBlt.
  41. *
  42. * Note that we have no way of determining what the current Rop or brush
  43. * alignment are at this point.
  44. *
  45. \**************************************************************************/
  46. BOOL DrvRealizeBrush(
  47. BRUSHOBJ* pbo,
  48. SURFOBJ* psoDst,
  49. SURFOBJ* psoPattern,
  50. SURFOBJ* psoMask,
  51. XLATEOBJ* pxlo,
  52. ULONG iHatch)
  53. {
  54. PDEV* ppdev;
  55. ULONG iPatternFormat;
  56. BYTE* pjSrc;
  57. BYTE* pjDst;
  58. LONG lSrcDelta;
  59. LONG cj;
  60. LONG i;
  61. LONG j;
  62. RBRUSH* prb;
  63. ULONG* pulXlate;
  64. SURFOBJ* psoPunt;
  65. RECTL rclDst;
  66. BOOL b;
  67. ppdev = (PDEV*) psoDst->dhpdev;
  68. // We only handle brushes if we have an off-screen brush cache
  69. // available. If there isn't one, we can simply fail the realization,
  70. // and eventually GDI will do the drawing for us (although a lot
  71. // slower than we could have done it):
  72. if (!(ppdev->flStatus & STAT_BRUSH_CACHE))
  73. goto ReturnFalse;
  74. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  75. if (iHatch & RB_DITHERCOLOR)
  76. {
  77. // Implementing DITHERONREALIZE increased our score on a certain
  78. // unmentionable benchmark by 0.4 million 'megapixels'. Too bad
  79. // this didn't work in the first version of NT.
  80. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  81. sizeof(RBRUSH) + CONVERT_TO_BYTES(TOTAL_BRUSH_SIZE, ppdev));
  82. if (prb == NULL)
  83. goto ReturnFalse;
  84. vRealizeDitherPattern(psoDst->hdev, prb, iHatch);
  85. goto ReturnTrue;
  86. }
  87. // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  88. // support patterns of any other size, it's a safe bet that 99.9%
  89. // of the patterns we'll ever get will be 8x8:
  90. if ((psoPattern->sizlBitmap.cx != 8) ||
  91. (psoPattern->sizlBitmap.cy != 8))
  92. goto ReturnFalse;
  93. iPatternFormat = psoPattern->iBitmapFormat;
  94. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  95. sizeof(RBRUSH) + CONVERT_TO_BYTES(TOTAL_BRUSH_SIZE, ppdev));
  96. if (prb == NULL)
  97. goto ReturnFalse;
  98. // Initialize the fields we need:
  99. prb->ptlBrushOrg.x = LONG_MIN;
  100. prb->fl = 0;
  101. prb->pbe = NULL;
  102. lSrcDelta = psoPattern->lDelta;
  103. pjSrc = (BYTE*) psoPattern->pvScan0;
  104. pjDst = (BYTE*) &prb->aulPattern[0];
  105. if ((ppdev->iBitmapFormat == iPatternFormat) &&
  106. ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
  107. {
  108. DISPDBG((1, "Realizing un-translated brush"));
  109. // The pattern is the same colour depth as the screen, and
  110. // there's no translation to be done:
  111. cj = CONVERT_TO_BYTES(8, ppdev); // Every pattern is 8 pels wide
  112. for (i = 8; i != 0; i--)
  113. {
  114. RtlCopyMemory(pjDst, pjSrc, cj);
  115. pjSrc += lSrcDelta;
  116. pjDst += cj;
  117. }
  118. }
  119. // Don't do monochrome expansion on 24 bpp due to s3 968 feature.
  120. else if ((iPatternFormat == BMF_1BPP) && (ppdev->iBitmapFormat != BMF_24BPP))
  121. {
  122. DISPDBG((1, "Realizing 1bpp brush"));
  123. // We word align the monochrome bitmap so that every row starts
  124. // on a new word (so that we can do word writes later to transfer
  125. // the bitmap):
  126. for (i = 8; i != 0; i--)
  127. {
  128. *pjDst = *pjSrc;
  129. pjDst += sizeof(WORD);
  130. pjSrc += lSrcDelta;
  131. }
  132. pulXlate = pxlo->pulXlate;
  133. prb->fl |= RBRUSH_2COLOR;
  134. prb->ulForeColor = pulXlate[1];
  135. prb->ulBackColor = pulXlate[0];
  136. }
  137. else if ((iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  138. {
  139. DISPDBG((1, "Realizing 4bpp brush"));
  140. // The screen is 8bpp and the pattern is 4bpp:
  141. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  142. (iPatternFormat == BMF_4BPP),
  143. "Messed up brush logic");
  144. pulXlate = pxlo->pulXlate;
  145. for (i = 8; i != 0; i--)
  146. {
  147. // Inner loop is repeated only 4 times because each loop
  148. // handles 2 pixels:
  149. for (j = 4; j != 0; j--)
  150. {
  151. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  152. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  153. pjSrc++;
  154. }
  155. pjSrc += lSrcDelta - 4;
  156. }
  157. }
  158. else
  159. {
  160. // We've got a brush whose format we haven't special cased. No
  161. // problem, we can have GDI convert it to our device's format.
  162. // We simply use a temporary surface object that was created with
  163. // the same format as the display, and point it to our brush
  164. // realization:
  165. DISPDBG((5, "Realizing funky brush"));
  166. psoPunt = ppdev->psoBank;
  167. psoPunt->pvScan0 = pjDst;
  168. psoPunt->lDelta = CONVERT_TO_BYTES(8, ppdev);
  169. rclDst.left = 0;
  170. rclDst.top = 0;
  171. rclDst.right = 8;
  172. rclDst.bottom = 8;
  173. b = EngCopyBits(psoPunt, psoPattern, NULL, pxlo,
  174. &rclDst, (POINTL*) &rclDst);
  175. if (!b)
  176. {
  177. goto ReturnFalse;
  178. }
  179. }
  180. ReturnTrue:
  181. if (!(ppdev->flCaps & CAPS_HW_PATTERNS))
  182. {
  183. // The last time I checked, GDI took some 500 odd instructions to
  184. // get from here back to whereever we called 'BRUSHOBJ_pvGetRbrush'.
  185. // We can at least use this time to get some overlap between the
  186. // CPU and the display hardware: we'll initialize the 72x72 off-
  187. // screen cache entry now, which will keep the accelerator busy for
  188. // a while.
  189. //
  190. // We don't do this if we have hardware patterns because:
  191. //
  192. // a) S3 hardware patterns require that the off-screen cached
  193. // brush be correctly aligned, and at this point we don't have
  194. // access to the 'pptlBrush' brush origin (although we could
  195. // have copied it into the PDEV before calling
  196. // BRUSHOBJ_pvGetRbrush).
  197. //
  198. // b) S3 hardware patterns require only an 8x8 copy of the
  199. // pattern; it is not expanded to 72x72, so there isn't even
  200. // any opportunity for CPU/accelerator processing overlap.
  201. vIoSlowPatRealize(ppdev, prb, FALSE);
  202. }
  203. return(TRUE);
  204. ReturnFalse:
  205. if (psoPattern != NULL)
  206. {
  207. DISPDBG((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  208. psoPattern->iType, psoPattern->iBitmapFormat,
  209. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  210. }
  211. return(FALSE);
  212. }
  213. /******************************Public*Routine******************************\
  214. * BOOL bEnableBrushCache
  215. *
  216. * Allocates off-screen memory for storing the brush cache.
  217. \**************************************************************************/
  218. BOOL bEnableBrushCache(
  219. PDEV* ppdev)
  220. {
  221. DSURF* pdsurf;
  222. BRUSHENTRY* pbe; // Pointer to the brush-cache entry
  223. LONG i;
  224. LONG j;
  225. LONG x;
  226. LONG y;
  227. // Since the DirectDraw heap isn't enabled yet, we allocate memory
  228. // simply by chopping a row off the bottom of memory.
  229. pbe = &ppdev->abe[0]; // Points to where we'll put the first brush
  230. // cache entry
  231. if (ppdev->flCaps & CAPS_HW_PATTERNS)
  232. {
  233. if (ppdev->cyScreen > ppdev->cyHeap - FAST_BRUSH_ALLOCATION)
  234. goto ReturnTrue;
  235. ppdev->cyHeap -= FAST_BRUSH_ALLOCATION;
  236. x = 0;
  237. y = ppdev->cyHeap;
  238. ppdev->cBrushCache = FAST_BRUSH_COUNT;
  239. // Hardware brushes require that the x-coordinate start on an 8
  240. // pixel boundary. The heap manager doesn't guarantee us any such
  241. // alignment, so we allocate a bit of extra room so that we can
  242. // do the alignment ourselves:
  243. for (i = FAST_BRUSH_COUNT; i != 0; i--)
  244. {
  245. // If we hadn't allocated 'ppdev' so that it was zero initialized,
  246. // we would have to initialize pbe->prbVerify too...
  247. pbe->x = x;
  248. pbe->y = y;
  249. x += FAST_BRUSH_ALLOCATION;
  250. pbe++;
  251. }
  252. // Remember the location of our 1x8 work area, which will be at
  253. // the right end of our brush array:
  254. ppdev->ptlReRealize.x = x;
  255. ppdev->ptlReRealize.y = y;
  256. }
  257. else
  258. {
  259. ppdev->pfnFillPat = vIoFillPatSlow; // Override FillPatFast
  260. if (ppdev->cyScreen > ppdev->cyHeap - SLOW_BRUSH_CACHE_DIM
  261. * SLOW_BRUSH_ALLOCATION)
  262. goto ReturnTrue;
  263. ppdev->cyHeap -= SLOW_BRUSH_CACHE_DIM * SLOW_BRUSH_ALLOCATION;
  264. x = 0;
  265. y = ppdev->cyHeap;
  266. ppdev->cBrushCache = SLOW_BRUSH_COUNT;
  267. for (i = 0; i < SLOW_BRUSH_CACHE_DIM; i++)
  268. {
  269. for (j = 0; j < SLOW_BRUSH_CACHE_DIM; j++)
  270. {
  271. pbe->x = x + (i * SLOW_BRUSH_ALLOCATION);
  272. pbe->y = y + (j * SLOW_BRUSH_ALLOCATION);
  273. pbe++;
  274. }
  275. }
  276. }
  277. // We successfully allocated the brush cache, so let's turn
  278. // on the switch showing that we can use it:
  279. ppdev->flStatus |= STAT_BRUSH_CACHE;
  280. ReturnTrue:
  281. // If we couldn't allocate a brush cache, it's not a catastrophic
  282. // failure; patterns will still work, although they'll be a bit
  283. // slower since they'll go through GDI. As a result we don't
  284. // actually have to fail this call:
  285. DISPDBG((5, "Passed bEnableBrushCache"));
  286. return(TRUE);
  287. }
  288. /******************************Public*Routine******************************\
  289. * VOID vDisableBrushCache
  290. *
  291. * Cleans up anything done in bEnableBrushCache.
  292. \**************************************************************************/
  293. VOID vDisableBrushCache(PDEV* ppdev)
  294. {
  295. }
  296. /******************************Public*Routine******************************\
  297. * VOID vAssertModeBrushCache
  298. *
  299. * Resets the brush cache when we exit out of full-screen.
  300. \**************************************************************************/
  301. VOID vAssertModeBrushCache(
  302. PDEV* ppdev,
  303. BOOL bEnable)
  304. {
  305. BRUSHENTRY* pbe;
  306. LONG i;
  307. if (bEnable)
  308. {
  309. // Invalidate the brush cache:
  310. pbe = &ppdev->abe[0];
  311. for (i = ppdev->cBrushCache; i != 0; i--)
  312. {
  313. pbe->prbVerify = NULL;
  314. pbe++;
  315. }
  316. }
  317. }