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.

383 lines
11 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. PDEV* ppdev,
  19. RBRUSH* prb,
  20. ULONG ulRGBToDither)
  21. {
  22. ULONG ulNumVertices;
  23. VERTEX_DATA vVertexData[4];
  24. VERTEX_DATA* pvVertexData;
  25. LONG i;
  26. // Calculate what colour 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. // Initialize the fields we need:
  35. prb->fl = 0;
  36. prb->pfnFillPat = ppdev->pfnFillPatColor;
  37. for (i = 0; i < MAX_BOARDS; i++)
  38. {
  39. prb->apbe[i] = NULL;
  40. }
  41. }
  42. /******************************Public*Routine******************************\
  43. * BOOL DrvRealizeBrush
  44. *
  45. * This function allows us to convert GDI brushes into an internal form
  46. * we can use. It may be called directly by GDI at SelectObject time, or
  47. * it may be called by GDI as a result of us calling BRUSHOBJ_pvGetRbrush
  48. * to create a realized brush in a function like DrvBitBlt.
  49. *
  50. * Note that we have no way of determining what the current Rop or brush
  51. * alignment are at this point.
  52. *
  53. \**************************************************************************/
  54. BOOL DrvRealizeBrush(
  55. BRUSHOBJ* pbo,
  56. SURFOBJ* psoDst,
  57. SURFOBJ* psoPattern,
  58. SURFOBJ* psoMask,
  59. XLATEOBJ* pxlo,
  60. ULONG iHatch)
  61. {
  62. PDEV* ppdev;
  63. ULONG iPatternFormat;
  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. BOOL b;
  75. ppdev = (PDEV*) psoDst->dhpdev;
  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->cjPelSize));
  84. if (prb == NULL)
  85. goto ReturnFalse;
  86. vRealizeDitherPattern(ppdev, prb, iHatch);
  87. goto ReturnTrue;
  88. }
  89. // We only accelerate 8x8 patterns. Since Win3.1 and Chicago don't
  90. // support patterns of any other size, it's a safe bet that 99.9%
  91. // of the patterns we'll ever get will be 8x8:
  92. if ((psoPattern->sizlBitmap.cx != 8) ||
  93. (psoPattern->sizlBitmap.cy != 8))
  94. goto ReturnFalse;
  95. if (!(ppdev->flCaps & CAPS_COLOR_PATTERNS))
  96. {
  97. // If for whatever reason we can't support colour patterns in
  98. // this mode, the only alternative left is to support
  99. // monochrome patterns:
  100. if (!(ppdev->flCaps & CAPS_MONOCHROME_PATTERNS) ||
  101. (psoPattern->iBitmapFormat != BMF_1BPP))
  102. goto ReturnFalse;
  103. }
  104. iPatternFormat = psoPattern->iBitmapFormat;
  105. prb = BRUSHOBJ_pvAllocRbrush(pbo,
  106. sizeof(RBRUSH) + (TOTAL_BRUSH_SIZE * ppdev->cjPelSize));
  107. if (prb == NULL)
  108. goto ReturnFalse;
  109. // Initialize the fields we need:
  110. prb->fl = 0;
  111. prb->pfnFillPat = ppdev->pfnFillPatColor;
  112. for (i = 0; i < MAX_BOARDS; i++)
  113. {
  114. prb->apbe[i] = NULL;
  115. }
  116. lSrcDelta = psoPattern->lDelta;
  117. pjSrc = (BYTE*) psoPattern->pvScan0;
  118. pjDst = (BYTE*) &prb->aulPattern[0];
  119. if ((ppdev->iBitmapFormat == iPatternFormat) &&
  120. ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)))
  121. {
  122. DISPDBG((1, "Realizing un-translated brush"));
  123. // The pattern is the same colour depth as the screen, and
  124. // there's no translation to be done:
  125. cj = (8 * ppdev->cjPelSize); // Every pattern is 8 pels wide
  126. for (i = 8; i != 0; i--)
  127. {
  128. RtlCopyMemory(pjDst, pjSrc, cj);
  129. pjSrc += lSrcDelta;
  130. pjDst += cj;
  131. }
  132. }
  133. else if ((iPatternFormat == BMF_1BPP) &&
  134. (ppdev->flCaps & CAPS_MONOCHROME_PATTERNS))
  135. {
  136. DISPDBG((1, "Realizing 1bpp brush"));
  137. for (i = 8; i != 0; i--)
  138. {
  139. *pjDst = *pjSrc;
  140. pjDst++;
  141. pjSrc += lSrcDelta;
  142. }
  143. pulXlate = pxlo->pulXlate;
  144. prb->fl |= RBRUSH_2COLOR;
  145. prb->ulForeColor = pulXlate[1];
  146. prb->ulBackColor = pulXlate[0];
  147. prb->ptlBrush.x = 0;
  148. prb->ptlBrush.y = 0;
  149. prb->pfnFillPat = ppdev->pfnFillPatMonochrome;
  150. }
  151. else if ((iPatternFormat == BMF_4BPP) && (ppdev->iBitmapFormat == BMF_8BPP))
  152. {
  153. DISPDBG((1, "Realizing 4bpp brush"));
  154. // The screen is 8bpp and the pattern is 4bpp:
  155. ASSERTDD((ppdev->iBitmapFormat == BMF_8BPP) &&
  156. (iPatternFormat == BMF_4BPP),
  157. "Messed up brush logic");
  158. pulXlate = pxlo->pulXlate;
  159. for (i = 8; i != 0; i--)
  160. {
  161. // Inner loop is repeated only 4 times because each loop
  162. // handles 2 pixels:
  163. for (j = 4; j != 0; j--)
  164. {
  165. *pjDst++ = (BYTE) pulXlate[*pjSrc >> 4];
  166. *pjDst++ = (BYTE) pulXlate[*pjSrc & 15];
  167. pjSrc++;
  168. }
  169. pjSrc += lSrcDelta - 4;
  170. }
  171. }
  172. else
  173. {
  174. // We've got a brush whose format we haven't special cased. No
  175. // problem, we can have GDI convert it to our device's format.
  176. // We simply use a temporary surface object that was created with
  177. // the same format as the display, and point it to our brush
  178. // realization:
  179. DISPDBG((5, "Realizing funky brush"));
  180. psoPunt = ppdev->psoBank;
  181. psoPunt->pvScan0 = pjDst;
  182. psoPunt->lDelta = 8 * ppdev->cjPelSize;
  183. rclDst.left = 0;
  184. rclDst.top = 0;
  185. rclDst.right = 8;
  186. rclDst.bottom = 8;
  187. b = EngCopyBits(psoPunt, psoPattern, NULL, pxlo,
  188. &rclDst, (POINTL*) &rclDst);
  189. if (!b)
  190. {
  191. goto ReturnFalse;
  192. }
  193. }
  194. ReturnTrue:
  195. return(TRUE);
  196. ReturnFalse:
  197. if (psoPattern != NULL)
  198. {
  199. DISPDBG((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  200. psoPattern->iType, psoPattern->iBitmapFormat,
  201. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  202. }
  203. return(FALSE);
  204. }
  205. /******************************Public*Routine******************************\
  206. * BOOL bEnableBrushCache
  207. *
  208. * Allocates off-screen memory for storing the brush cache.
  209. \**************************************************************************/
  210. BOOL bEnableBrushCache(
  211. PDEV* ppdev)
  212. {
  213. OH* poh;
  214. BRUSHENTRY* pbe;
  215. LONG i;
  216. LONG x;
  217. LONG y;
  218. ULONG ulOffset;
  219. if ((ppdev->iMachType == MACH_MM_32) || (ppdev->iMachType == MACH_IO_32))
  220. {
  221. if (ppdev->iBitmapFormat == BMF_8BPP)
  222. {
  223. // All Mach8 and Mach32 cards can handle colour patterns in
  224. // the hardware when running at 8bpp:
  225. ppdev->flCaps |= CAPS_COLOR_PATTERNS;
  226. }
  227. if ((ppdev->iAsic == ASIC_68800_6) || (ppdev->iAsic == ASIC_68800AX))
  228. {
  229. // Some Mach32 ASICs can handle 8x8 monochrome patterns directly
  230. // in the hardware:
  231. ppdev->flCaps |= CAPS_MONOCHROME_PATTERNS;
  232. }
  233. }
  234. else
  235. {
  236. ASSERTDD(ppdev->iMachType == MACH_MM_64, "Weird other case?");
  237. // All Mach64's can handle 8x8 monochrome patterns directly:
  238. ppdev->flCaps |= CAPS_MONOCHROME_PATTERNS;
  239. // Allocate some off-screen memory for a brush cache:
  240. if (ppdev->cxMemory >= TOTAL_BRUSH_SIZE * TOTAL_BRUSH_COUNT)
  241. {
  242. poh = pohAllocate(ppdev, NULL, ppdev->cxMemory, 1,
  243. FLOH_MAKE_PERMANENT);
  244. if (poh != NULL)
  245. {
  246. ppdev->flCaps |= CAPS_COLOR_PATTERNS;
  247. pbe = &ppdev->abe[0]; // Points to where we'll put the first
  248. // brush cache entry
  249. x = poh->x;
  250. y = poh->y;
  251. for (i = TOTAL_BRUSH_COUNT; i != 0; i--)
  252. {
  253. // If we hadn't allocated 'ppdev' so that it was zero
  254. // initialized, we would have to initialize pbe->prbVerify
  255. // too...
  256. pbe->x = x;
  257. pbe->y = y;
  258. // !!! Test at 24bpp on banked Mach64!
  259. ulOffset = ((y * ppdev->lDelta) + (x * ppdev->cjPelSize)
  260. + ppdev->ulTearOffset) >> 3;
  261. // The pitch of the brush is 8 pixels, and must be scaled
  262. // up by 8:
  263. if (ppdev->iBitmapFormat != BMF_24BPP)
  264. pbe->ulOffsetPitch = PACKPAIR(ulOffset, 8 * 8);
  265. else
  266. pbe->ulOffsetPitch = PACKPAIR(ulOffset, 3 * 8 * 8); // 24bpp is actually 8bpp internally
  267. x += TOTAL_BRUSH_SIZE;
  268. pbe++;
  269. }
  270. }
  271. }
  272. }
  273. return(TRUE);
  274. }
  275. /******************************Public*Routine******************************\
  276. * VOID vDisableBrushCache
  277. *
  278. * Cleans up anything done in bEnableBrushCache.
  279. \**************************************************************************/
  280. VOID vDisableBrushCache(PDEV* ppdev)
  281. {
  282. // We ain't gotta do nothin'
  283. }
  284. /******************************Public*Routine******************************\
  285. * VOID vAssertModeBrushCache
  286. *
  287. * Resets the brush cache when we exit out of full-screen.
  288. \**************************************************************************/
  289. VOID vAssertModeBrushCache(
  290. PDEV* ppdev,
  291. BOOL bEnable)
  292. {
  293. BRUSHENTRY* pbe;
  294. LONG i;
  295. if (bEnable)
  296. {
  297. // Invalidate the brush cache:
  298. pbe = &ppdev->abe[0];
  299. for (i = TOTAL_BRUSH_COUNT; i != 0; i--)
  300. {
  301. pbe->prbVerify = NULL;
  302. pbe++;
  303. }
  304. }
  305. }