Leaked source code of windows server 2003
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.

491 lines
17 KiB

  1. /******************************Module*Header*******************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: brush.c
  8. *
  9. * Content: Handles all brush/pattern initialization and realization.
  10. *
  11. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  12. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  13. \**************************************************************************/
  14. #include "precomp.h"
  15. #include "heap.h"
  16. //-----------------------------------------------------------------------------
  17. //
  18. // VOID vRealizeDitherPattern
  19. //
  20. // Generates an 8x8 dither pattern, in our internal realization format, for
  21. // the colour ulRGBToDither.
  22. //
  23. //-----------------------------------------------------------------------------
  24. VOID
  25. vRealizeDitherPattern(HDEV hdev,
  26. RBrush* prb,
  27. ULONG ulRGBToDither)
  28. {
  29. //
  30. // Do the actual dithering
  31. // Note: This function is NT5 only. If you want to write a NT4 driver,
  32. // you have to implement dither function in the driver
  33. //
  34. EngDitherColor(hdev, DM_DEFAULT, ulRGBToDither, &prb->aulPattern[0]);
  35. //
  36. // Initialize the fields we need
  37. //
  38. prb->ptlBrushOrg.x = LONG_MIN;
  39. prb->fl = 0;
  40. prb->pbe = NULL;
  41. }// vRealizeDitherPattern()
  42. //---------------------------Public*Routine------------------------------------
  43. //
  44. // BOOL DrvRealizeBrush
  45. //
  46. // This function allows us to convert GDI brushes into an internal form
  47. // we can use. It is called by GDI when we've called BRUSHOBJ_pvGetRbrush
  48. // in some other function like DrvBitBlt, and GDI doesn't happen have a cached
  49. // realization lying around.
  50. //
  51. // Parameters:
  52. // pbo----------Points to the BRUSHOBJ that is to be realized. All other
  53. // parameters, except for psoTarget, can be queried from this
  54. // object. Parameter specifications are provided as an
  55. // optimization. This parameter is best used only as a parameter
  56. // for BRUSHOBJ_pvAllocRBrush, which allocates the memory for the
  57. // realized brush.
  58. // psoTarget----Points to the surface for which the brush is to be realized.
  59. // This surface can be the physical surface for the device, a
  60. // device format bitmap, or a standard format bitmap.
  61. // psoPattern---Points to the surface that describes the pattern for the brush.
  62. // For a raster device, this is a bitmap. For a vector device,
  63. // this is one of the pattern surfaces provided by DrvEnablePDEV.
  64. // psoMask------Points to a transparency mask for the brush. This is a 1 bit
  65. // per pixel bitmap that has the same extent as the pattern. A
  66. // mask of zero means the pixel is considered a background pixel
  67. // for the brush. (In transparent background mode, the background
  68. // pixels are unaffected in a fill.) Plotters can ignore this
  69. // parameter because they never draw background information.
  70. // pxlo---------Points to a XLATEOBJ that defines the interpretration of colors
  71. // in the pattern. A XLATEOBJXxx service routine can be called to
  72. // translate the colors to device color indices. Vector devices
  73. // should translate color zero through the XLATEOBJ to get the
  74. // foreground color for the brush.
  75. // ulHatch------Specifies whether psoPattern is one of the hatch brushes
  76. // returned by DrvEnablePDEV. This is true if the value of this
  77. // parameter is less than HS_API_MAX.
  78. //
  79. // Return Value
  80. // The return value is TRUE if the brush was successfully realized. Otherwise,
  81. // it is FALSE, and an error code is logged.
  82. //
  83. // Comments
  84. // To realize a brush, the driver converts a GDI brush into a form that can be
  85. // used internally. A realized brush contains information and accelerators the
  86. // driver needs to fill an area with a pattern; information that is defined by
  87. // the driver and used only by the driver.
  88. //
  89. // The driver's realization of a brush is written into the buffer allocated by
  90. // a call to BRUSHOBJ_pvAllocRbrush.
  91. //
  92. // DrvRealizeBrush is required for a driver that does any drawing to any
  93. // surface.
  94. //
  95. // ppdev->bRealizeTransparent -- Hint for whether or not the brush should be
  96. // realized for transparency. If this hint is
  97. // wrong, there will be no error, but the brush
  98. // will have to be unnecessarily re-realized.
  99. //
  100. // Note: You should always set 'ppdev->bRealizeTransparent' before calling
  101. // BRUSHOBJ_pvGetRbrush!
  102. //
  103. //-----------------------------------------------------------------------------
  104. BOOL
  105. DrvRealizeBrush(BRUSHOBJ* pbo,
  106. SURFOBJ* psoDst,
  107. SURFOBJ* psoPattern,
  108. SURFOBJ* psoMask,
  109. XLATEOBJ* pxlo,
  110. ULONG ulHatch)
  111. {
  112. PDev* ppdev = (PDev*)psoDst->dhpdev;
  113. BYTE* pbDst;
  114. BYTE* pbSrc;
  115. LONG i;
  116. LONG j;
  117. LONG lNumPixelToBeCopied;
  118. LONG lSrcDelta;
  119. RBrush* prb;
  120. ULONG* pulXlate;
  121. ULONG ulPatternFormat;
  122. PERMEDIA_DECL;
  123. DBG_GDI((6, "DrvRealizeBrush called for pbo 0x%x", pbo));
  124. //
  125. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE:
  126. //
  127. if ( ulHatch & RB_DITHERCOLOR )
  128. {
  129. //
  130. // Move this test in here since we always support monochrome brushes
  131. // as they live in the on-chip area stipple. These dithered brushes
  132. // will always be colored requiring available off-screen memory.
  133. //
  134. if ( !(ppdev->flStatus & STAT_BRUSH_CACHE) )
  135. {
  136. //
  137. // We only handle brushes if we have an off-screen brush cache
  138. // available. If there isn't one, we can simply fail the
  139. // realization, and eventually GDI will do the drawing for us
  140. // (although a lot slower than we could have done it)
  141. //
  142. DBG_GDI((6, "brush cache not enabled"));
  143. goto ReturnFalse;
  144. }
  145. DBG_GDI((7, "DITHERONREALIZE"));
  146. //
  147. // We have a fast path for dithers when we set GCAPS_DITHERONREALIZE
  148. // First, we need to allocate memory for the realization of a brush
  149. // Note: actually we ask for allocation of a RBRUSH + the brush
  150. // stamp size
  151. //
  152. prb = (RBrush*)BRUSHOBJ_pvAllocRbrush(pbo,
  153. sizeof(RBrush) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
  154. if ( prb == NULL )
  155. {
  156. DBG_GDI((1, "BRUSHOBJ_pvAllocRbrush() in dither return NULL\n"));
  157. goto ReturnFalse;
  158. }
  159. //
  160. // Dither and realize the brsuh pattern
  161. //
  162. vRealizeDitherPattern(psoDst->hdev, prb, ulHatch);
  163. goto ReturnTrue;
  164. }// if ( ulHatch & RB_DITHERCOLOR )
  165. //
  166. // We only handle brushes if we have an off-screen brush cache available
  167. // If there isn't one, we can simply fail the realization, and eventually
  168. // GDI will do the drawing for us (although a lot slower than we could have
  169. // done it). We always succeed for 1bpp patterns since we use the area
  170. // stipple unit to do these rather than off-screen memory.
  171. //
  172. ulPatternFormat = psoPattern->iBitmapFormat;
  173. if ( !(ppdev->flStatus & STAT_BRUSH_CACHE)
  174. &&(ulPatternFormat != BMF_1BPP) )
  175. {
  176. DBG_GDI((1, "brush cache not enabled, or Bitmap is not 1 BPP"));
  177. goto ReturnFalse;
  178. }
  179. //
  180. // We only accelerate 8x8 patterns since most of the video card can only
  181. // accelerate 8x8 brush
  182. //
  183. if ( (psoPattern->sizlBitmap.cx != 8)
  184. ||(psoPattern->sizlBitmap.cy != 8) )
  185. {
  186. DBG_GDI((1, "Brush Bitmap size is not 8x8"));
  187. goto ReturnFalse;
  188. }
  189. //
  190. // We need to allocate memory for the realization of a brush
  191. // Note: actually we ask for allocation of a RBRUSH + the brush stamp size
  192. //
  193. prb = (RBrush*)BRUSHOBJ_pvAllocRbrush(pbo,
  194. sizeof(RBrush) + (TOTAL_BRUSH_SIZE << ppdev->cPelSize));
  195. if ( prb == NULL )
  196. {
  197. DBG_GDI((0, "BRUSHOBJ_pvAllocRbrush() failed"));
  198. goto ReturnFalse;
  199. }
  200. //
  201. // Initialize the fields we need
  202. //
  203. prb->ptlBrushOrg.x = LONG_MIN;
  204. prb->fl = 0;
  205. prb->pbe = NULL;
  206. lSrcDelta = psoPattern->lDelta;
  207. pbSrc = (BYTE*)psoPattern->pvScan0;
  208. pbDst = (BYTE*)&prb->aulPattern[0];
  209. //
  210. // At 8bpp, we handle patterns at 1bpp, 4bpp and 8bpp with/without an xlate
  211. // At 16bpp, we handle patterns at 16 bpp without an xlate.
  212. // At 32bpp, we handle patterns at 32bpp without an xlate.
  213. // We handle all the patterns at 1 bpp with/without an Xlate
  214. //
  215. // Check if the brush pattern has the same color depth as our current
  216. // display color depth
  217. //
  218. if ( ulPatternFormat == BMF_1BPP )
  219. {
  220. DWORD Data;
  221. DBG_GDI((7, "Realizing 1bpp brush"));
  222. //
  223. // We dword align the monochrome bitmap so that every row starts
  224. // on a new long (so that we can do long writes later to transfer
  225. // the bitmap to the area stipple unit).
  226. //
  227. for ( i = 8; i != 0; i-- )
  228. {
  229. //
  230. // Replicate the brush to 32 bits wide, as the TX cannot
  231. // span fill 8 bit wide brushes
  232. //
  233. Data = (*pbSrc) & 0xff;
  234. Data |= Data << 8;
  235. Data |= Data << 16;
  236. *(DWORD*)pbDst = Data;
  237. //
  238. // Area stipple is loaded with DWORDS
  239. //
  240. pbDst += sizeof(DWORD);
  241. pbSrc += lSrcDelta;
  242. }
  243. pulXlate = pxlo->pulXlate;
  244. prb->fl |= RBRUSH_2COLOR;
  245. prb->ulForeColor = pulXlate[1];
  246. prb->ulBackColor = pulXlate[0];
  247. }// Pattern at 1 BPP
  248. else if ( (ulPatternFormat == BMF_4BPP)&&(ppdev->iBitmapFormat == BMF_8BPP))
  249. {
  250. DBG_GDI((7, "Realizing 4bpp brush"));
  251. //
  252. // The screen is 8bpp and the pattern is 4bpp:
  253. //
  254. pulXlate = pxlo->pulXlate;
  255. for ( i = 8; i != 0; i-- )
  256. {
  257. //
  258. // Inner loop is repeated only 4 times because each loop
  259. // handles 2 pixels:
  260. //
  261. for ( j = 4; j != 0; j-- )
  262. {
  263. *pbDst++ = (BYTE)pulXlate[*pbSrc >> 4];
  264. *pbDst++ = (BYTE)pulXlate[*pbSrc & 15];
  265. pbSrc++;
  266. }
  267. pbSrc += lSrcDelta - 4;
  268. }
  269. }// Pattern 4BPP and Screen 8 BPP
  270. else if ( ( ppdev->iBitmapFormat == ulPatternFormat )
  271. &&( (pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL) ) )
  272. {
  273. DBG_GDI((7, "Realizing un-translated brush"));
  274. //
  275. // The pattern is the same colour depth as the screen, and
  276. // there's no translation to be done.
  277. // Here we first need to calculate how many pixel need to be
  278. // copied
  279. //
  280. lNumPixelToBeCopied = (8 << ppdev->cPelSize);
  281. for ( i = 8; i != 0; i-- )
  282. {
  283. RtlCopyMemory(pbDst, pbSrc, lNumPixelToBeCopied);
  284. pbSrc += lSrcDelta;
  285. pbDst += lNumPixelToBeCopied;
  286. }
  287. }// Pattern and Screen has same color depth, No Xlate
  288. else if ( (ppdev->iBitmapFormat == BMF_8BPP)
  289. &&(ulPatternFormat == BMF_8BPP) )
  290. {
  291. DBG_GDI((7, "Realizing 8bpp translated brush"));
  292. //
  293. // The screen is 8bpp, and there's translation to be done
  294. // So we have to do copy + Xlate one by one
  295. //
  296. pulXlate = pxlo->pulXlate;
  297. for ( i = 8; i != 0; i-- )
  298. {
  299. for ( j = 8; j != 0; j-- )
  300. {
  301. *pbDst++ = (BYTE)pulXlate[*pbSrc++];
  302. }
  303. pbSrc += lSrcDelta - 8;
  304. }
  305. }// Screen mode and pattern mode all at 8 BPP
  306. else
  307. {
  308. //
  309. // We've got a brush whose format we haven't special cased.
  310. //
  311. goto ReturnFalse;
  312. }
  313. ReturnTrue:
  314. DBG_GDI((6, "DrvRealizeBrush returning true"));
  315. return(TRUE);
  316. ReturnFalse:
  317. if ( psoPattern != NULL )
  318. {
  319. DBG_GDI((1, "Failed realization -- Type: %li Format: %li cx: %li cy: %li",
  320. psoPattern->iType, psoPattern->iBitmapFormat,
  321. psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
  322. }
  323. DBG_GDI((6, "DrvRealizeBrush returning false"));
  324. return(FALSE);
  325. }// DrvRealizeBrush()
  326. //-----------------------------------------------------------------------------
  327. //
  328. // BOOL bEnableBrushCache
  329. //
  330. // Allocates off-screen memory for storing the brush cache.
  331. //
  332. //-----------------------------------------------------------------------------
  333. BOOL
  334. bEnableBrushCache(PDev* ppdev)
  335. {
  336. BrushEntry* pbe; // Pointer to the brush-cache entry
  337. LONG i;
  338. LONG lDelta;
  339. ULONG ulPixOffset;
  340. DBG_GDI((6, "bEnableBrushCache"));
  341. ASSERTDD(!(ppdev->flStatus & STAT_BRUSH_CACHE),
  342. "bEnableBrushCache: unexpected already enabled brush cache");
  343. //
  344. // ENABLE_BRUSH_CACHE by default is on. It would be turned off in
  345. // bInitializeHw() if 3D buffers runs out of memory
  346. //
  347. if ( !(ppdev->flStatus & ENABLE_BRUSH_CACHE) )
  348. {
  349. DBG_GDI((1, "Brush cache not valid for creation"));
  350. goto ReturnTrue;
  351. }
  352. ppdev->ulBrushVidMem = ulVidMemAllocate(ppdev,
  353. CACHED_BRUSH_WIDTH,
  354. CACHED_BRUSH_HEIGHT
  355. *NUM_CACHED_BRUSHES,
  356. ppdev->cPelSize,
  357. &lDelta,
  358. &ppdev->pvmBrushHeap,
  359. &ppdev->ulBrushPackedPP,
  360. FALSE);
  361. if (ppdev->ulBrushVidMem == 0 )
  362. {
  363. DBG_GDI((0, "bEnableBrushCache: failed to allocate video memory"));
  364. goto ReturnTrue; // See note about why we can return TRUE...
  365. }
  366. ASSERTDD(lDelta == (CACHED_BRUSH_WIDTH << ppdev->cPelSize),
  367. "bEnableBrushCache: unexpected stride does not match width");
  368. ppdev->cBrushCache = NUM_CACHED_BRUSHES;
  369. ulPixOffset = (ULONG) ppdev->ulBrushVidMem >> ppdev->cPelSize;
  370. pbe = &ppdev->abe[0];
  371. for (i = 0; i < NUM_CACHED_BRUSHES; i++, pbe++)
  372. {
  373. pbe->prbVerify = NULL;
  374. pbe->ulPixelOffset = ulPixOffset;
  375. ulPixOffset += CACHED_BRUSH_SIZE;
  376. memset((pbe->ulPixelOffset << ppdev->cPelSize) + ppdev->pjScreen,
  377. 0x0, (CACHED_BRUSH_SIZE << ppdev->cPelSize));
  378. }
  379. //
  380. // We successfully allocated the brush cache, so let's turn
  381. // on the switch showing that we can use it:
  382. //
  383. DBG_GDI((6, "bEnableBrushCache: successfully allocated brush cache"));
  384. ppdev->flStatus |= STAT_BRUSH_CACHE;
  385. ReturnTrue:
  386. //
  387. // If we couldn't allocate a brush cache, it's not a catastrophic
  388. // failure; patterns will still work, although they'll be a bit
  389. // slower since they'll go through GDI. As a result we don't
  390. // actually have to fail this call:
  391. //
  392. DBG_GDI((6, "Passed bEnableBrushCache"));
  393. return(TRUE);
  394. }// bEnableBrushCache()
  395. //-----------------------------------------------------------------------------
  396. //
  397. // VOID vDisableBrushCache
  398. //
  399. // Cleans up anything done in bEnableBrushCache.
  400. //
  401. //-----------------------------------------------------------------------------
  402. VOID
  403. vDisableBrushCache(PDev* ppdev)
  404. {
  405. DBG_GDI((6,"vDisableBrushCache"));
  406. if(ppdev->flStatus & STAT_BRUSH_CACHE)
  407. {
  408. DBG_GDI((6,"vDisableBrushCache: freeing brush cache"));
  409. VidMemFree(ppdev->pvmBrushHeap->lpHeap,
  410. (FLATPTR)(ppdev->ulBrushVidMem));
  411. ppdev->cBrushCache = 0;
  412. ppdev->flStatus &= ~STAT_BRUSH_CACHE;
  413. DBG_GDI((6,"vDisableBrushCache: freeing brush cache done"));
  414. }
  415. }// vDisableBrushCache()
  416. //-----------------------------------------------------------------------------
  417. //
  418. // VOID vAssertModeBrushCache
  419. //
  420. // Resets the brush cache when we exit out of full-screen.
  421. //
  422. //-----------------------------------------------------------------------------
  423. VOID
  424. vAssertModeBrushCache(PDev* ppdev,
  425. BOOL bEnable)
  426. {
  427. if ( bEnable )
  428. {
  429. bEnableBrushCache(ppdev);
  430. }
  431. else
  432. {
  433. vDisableBrushCache(ppdev);
  434. }
  435. }// vAssertModeBrushCache()