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.

607 lines
18 KiB

  1. /**************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * <an unabbreviated name for the module (not the filename)>
  8. *
  9. * Abstract:
  10. *
  11. * <Description of what this module does>
  12. *
  13. * Notes:
  14. *
  15. * <optional>
  16. *
  17. * Created:
  18. *
  19. * 04/23/2000 asecchia
  20. * Created it.
  21. *
  22. **************************************************************************/
  23. #include "precomp.hpp"
  24. /**************************************************************************
  25. *
  26. * Function Description:
  27. *
  28. * This function renders the GpCachedBitmap on the GpGraphics.
  29. *
  30. * Arguments:
  31. *
  32. * inputCachedBitmap - the input data.
  33. * x, y - destination offset.
  34. *
  35. * Return Value:
  36. *
  37. * Returns Ok if successful
  38. * Returs WrongState if the GpGraphics and GpCachedBitmap have
  39. * different pixel formats.
  40. *
  41. * Created:
  42. *
  43. * 04/23/2000 asecchia
  44. * Created it.
  45. *
  46. **************************************************************************/
  47. GpStatus
  48. GpGraphics::DrvDrawCachedBitmap(
  49. GpCachedBitmap *inputCachedBitmap,
  50. INT x,
  51. INT y
  52. )
  53. {
  54. // Internally we must be called with a valid object.
  55. ASSERT(inputCachedBitmap->IsValid());
  56. // Don't attempt to record a cached bitmap to a metafile
  57. if (IsRecording())
  58. return WrongState;
  59. // First grab the device lock so that we can protect all the
  60. // non-reentrant code in the DpScanBuffer class.
  61. Devlock devlock(Device);
  62. // Check the world transform
  63. if(!(Context->WorldToDevice.IsTranslate()))
  64. {
  65. // There is a complex transform selected into the graphics.
  66. // fail the call.
  67. return WrongState;
  68. }
  69. // Can't check the pixel format here because of the possibility of
  70. // MultiMon - we'd be checking against the meta device surface
  71. // -- although maybe that's the correct behaviour.
  72. // Set up the world to device translation offset.
  73. INT xOffset = x+GpRound(Context->WorldToDevice.GetDx());
  74. INT yOffset = y+GpRound(Context->WorldToDevice.GetDy());
  75. // Store the rendering origin so we can restore it later.
  76. INT renderX, renderY;
  77. GetRenderingOrigin(&renderX, &renderY);
  78. // Set the rendering origin to the origin of the CachedBitmap drawing
  79. // so that the dither matrix offset of the semi-transparent pixels
  80. // matches that of the already dithered (stored) native pixels.
  81. SetRenderingOrigin(xOffset, yOffset);
  82. // Call the driver to draw the cached bitmap.
  83. // Note: the driver does not respect the world to device transform
  84. // it expects device coordinates for this API.
  85. GpStatus status = Driver->DrawCachedBitmap(
  86. Context,
  87. &inputCachedBitmap->DeviceCachedBitmap,
  88. Surface,
  89. xOffset,
  90. yOffset
  91. );
  92. // Restore the rendering origin.
  93. SetRenderingOrigin(renderX, renderY);
  94. return status;
  95. }
  96. /**************************************************************************
  97. *
  98. * Function Description:
  99. *
  100. * Constructs the GpCachedBitmap based on the pixel format and
  101. * rendering quality derived from the GpGraphics and the bits
  102. * from the GpBitmap.
  103. *
  104. * Arguments:
  105. *
  106. * graphics - input graphics to be compatible with
  107. * bitmap - data to be cached.
  108. *
  109. * Return Value:
  110. *
  111. * NONE
  112. *
  113. * Created:
  114. *
  115. * 04/23/2000 asecchia
  116. * Created it.
  117. *
  118. **************************************************************************/
  119. enum TransparencyState {
  120. Transparent,
  121. SemiTransparent,
  122. Opaque
  123. };
  124. inline TransparencyState GetTransparency(ARGB pixel)
  125. {
  126. if((pixel & 0xff000000) == 0xff000000) {return Opaque;}
  127. if((pixel & 0xff000000) == 0x00000000) {return Transparent;}
  128. return SemiTransparent;
  129. }
  130. // Intermetiate record used to parse the transparency information
  131. // in the bitmap.
  132. struct ScanRecordTemp
  133. {
  134. // Pointer to the start and end of the run.
  135. ARGB *pStart;
  136. ARGB *pEnd; // exclusive end.
  137. // Transparency
  138. TransparencyState tsTransparent;
  139. // Position
  140. INT x, y;
  141. INT width; // in pixels
  142. };
  143. // Simple macro to make the failure cases easier to read.
  144. #define FAIL() \
  145. SetValid(FALSE); \
  146. return
  147. GpCachedBitmap::GpCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics)
  148. {
  149. BitmapData bmpDataSrc;
  150. // Lock the bits.
  151. // we need to convert the bits to the appropriate format.
  152. // Note - we're assuming that the knowledgeable user will be
  153. // initializing their CachedBitmap with a 32bppPARGB surface.
  154. // This is important for performance at creation time, because
  155. // the LockBits below can avoid a costly clone & convert format.
  156. if (bitmap == NULL ||
  157. !bitmap->IsValid() ||
  158. bitmap->LockBits(
  159. NULL,
  160. IMGLOCK_READ,
  161. PIXFMT_32BPP_PARGB,
  162. &bmpDataSrc
  163. )
  164. != Ok)
  165. {
  166. FAIL();
  167. }
  168. // copy the dimensions.
  169. DeviceCachedBitmap.Width = bmpDataSrc.Width;
  170. DeviceCachedBitmap.Height = bmpDataSrc.Height;
  171. // Create a dynamic array to store the transparency transition points.
  172. // The initial allocation size is based on an estimate of 3
  173. // transition events per scanline. Overestimate.
  174. DynArray<ScanRecordTemp> RunData;
  175. RunData.ReserveSpace(4*DeviceCachedBitmap.Height);
  176. // Scan through the bits adding an item to the dynamic list every
  177. // time a new run would be required in the output - i.e. when the
  178. // transparency changes to one of opaque or semi-transparent.
  179. // Before the beginning of a scanline is considered to be transparent.
  180. // While scanning through the bits, keep a running total of the
  181. // size of the final RLE bitmap - so we know how much space to allocate.
  182. // Size of the final RLE bitmap in bytes;
  183. // This is not actually a pointer to an EpScanRecord - it is simply
  184. // a mechanism to work out how big to allocate the buffer
  185. EpScanRecord *RLESize = (EpScanRecord *)0;
  186. // Pointer to the current position in the source.
  187. ARGB *src;
  188. ARGB *runStart;
  189. // Temporary ScanRecord used to accumulate the runs.
  190. ScanRecordTemp sctTmp;
  191. TransparencyState tsThisPixel;
  192. TransparencyState tsCurrentRun;
  193. DpBitmap *Surface = graphics->GetSurface();
  194. void *Buffers[5];
  195. // Create the blending buffers for the alpha blender.
  196. // !!! [asecchia] While we don't currently depend on this behaviour,
  197. // it seems like a bug that a graphics wrapped around a bitmap uses
  198. // the desktop display device and driver. This leads to weirdness
  199. // if we try use GetScanBuffers to derive the pixel format of the
  200. // destination. For example a graphics around a PixelFormat24bppRGB
  201. // bitmap would return PixelFormat16bppRGB565 if the screen is in
  202. // 16bpp mode !?
  203. // However, the Buffers[] returned will be allocated as 64bpp buffers
  204. // and therefore will have the correct properties under all circumstances.
  205. if (!graphics->GetDriver()->Device->GetScanBuffers(
  206. Surface->Width,
  207. NULL,
  208. NULL,
  209. NULL,
  210. Buffers)
  211. )
  212. {
  213. FAIL();
  214. }
  215. // Compute the destination pixel format.
  216. PixelFormatID dstFormat = Surface->PixelFormat;
  217. if(dstFormat == PixelFormatUndefined) { FAIL(); }
  218. // The following destination formats are not supported.
  219. // In particular, no palettized modes are supported because
  220. // tracking the cached opaque data in native format across
  221. // palette changes would be a nightmare.
  222. // Instead we set the opaque format to be 32bppRGB and force
  223. // the EpAlphaBlender to do the work at render time - slower
  224. // but it will work.
  225. if( !EpAlphaBlender::IsSupportedPixelFormat(dstFormat) ||
  226. IsIndexedPixelFormat(dstFormat) ||
  227. // If the graphics is for a multi format device such as
  228. // a multimon meta-screen.
  229. dstFormat == PixelFormatMulti
  230. )
  231. {
  232. // We don't want to silently fail if the input
  233. // is undefined.
  234. ASSERT(dstFormat != PixelFormatUndefined);
  235. // Opaque pixels - we don't support palettized modes
  236. // and some of the other weird ones
  237. dstFormat = PixelFormat32bppRGB;
  238. }
  239. // Size of a destination pixel in bytes.
  240. INT dstFormatSize = GetPixelFormatSize(dstFormat) >> 3;
  241. // Run through each scanline.
  242. for(INT y = 0; y < DeviceCachedBitmap.Height; y++)
  243. {
  244. // Point to the beginning of this scanline.
  245. src = reinterpret_cast<ARGB*>(
  246. reinterpret_cast<BYTE*>(bmpDataSrc.Scan0) + y * bmpDataSrc.Stride
  247. );
  248. // Start the run off with transparency.
  249. tsCurrentRun = Transparent;
  250. runStart = src;
  251. // Run through all the pixels in this scanline.
  252. for(INT x = 0; x < DeviceCachedBitmap.Width; x++)
  253. {
  254. // Compute the transparency state for the current pixel.
  255. tsThisPixel = GetTransparency(*src);
  256. // If a transparency transition occurs,
  257. if(tsThisPixel != tsCurrentRun)
  258. {
  259. // Close off the last transition and store a record if it wasn't
  260. // a transparent run.
  261. if(tsCurrentRun != Transparent)
  262. {
  263. sctTmp.pStart = runStart;
  264. sctTmp.pEnd = src;
  265. sctTmp.tsTransparent = tsCurrentRun;
  266. sctTmp.y = y;
  267. // src is in PixelFormat32bppPARGB so we can divide the
  268. // pointer difference by 4 to figure out the number of
  269. // pixels in this run.
  270. sctTmp.width = (INT)(((INT_PTR)src - (INT_PTR)runStart)/sizeof(ARGB));
  271. sctTmp.x = x - sctTmp.width;
  272. if(RunData.Add(sctTmp) != Ok) { FAIL(); }
  273. // Add the size of the record
  274. if (tsCurrentRun == SemiTransparent)
  275. {
  276. // This is the semi-transparent case.
  277. RLESize = EpScanRecord::CalculateNextScanRecord(
  278. RLESize,
  279. EpScanTypeBlend,
  280. sctTmp.width,
  281. sizeof(ARGB)
  282. );
  283. }
  284. else
  285. {
  286. // This is the opaque case.
  287. ASSERT(tsCurrentRun == Opaque);
  288. RLESize = EpScanRecord::CalculateNextScanRecord(
  289. RLESize,
  290. EpScanTypeOpaque,
  291. sctTmp.width,
  292. dstFormatSize
  293. );
  294. }
  295. }
  296. // Update the run tracking variables.
  297. runStart = src;
  298. tsCurrentRun = tsThisPixel;
  299. }
  300. // Look at the next pixel.
  301. src++;
  302. }
  303. // Close off the last run for this scanline (if it's not transparent).
  304. if(tsCurrentRun != Transparent)
  305. {
  306. sctTmp.pStart = runStart;
  307. sctTmp.pEnd = src;
  308. sctTmp.tsTransparent = tsCurrentRun;
  309. sctTmp.y = y;
  310. // Size of the source is 32bits (PARGB).
  311. sctTmp.width = (INT)(((INT_PTR)src - (INT_PTR)runStart)/sizeof(ARGB));
  312. sctTmp.x = x - sctTmp.width;
  313. if(RunData.Add(sctTmp)!=Ok) { FAIL(); }
  314. // Add the size of the record
  315. if (tsCurrentRun == SemiTransparent)
  316. {
  317. // This is the semi-transparent case.
  318. RLESize = EpScanRecord::CalculateNextScanRecord(
  319. RLESize,
  320. EpScanTypeBlend,
  321. sctTmp.width,
  322. sizeof(ARGB)
  323. );
  324. }
  325. else
  326. {
  327. // This is the opaque case.
  328. ASSERT(tsCurrentRun == Opaque);
  329. RLESize = EpScanRecord::CalculateNextScanRecord(
  330. RLESize,
  331. EpScanTypeOpaque,
  332. sctTmp.width,
  333. dstFormatSize
  334. );
  335. }
  336. }
  337. }
  338. ASSERT(RLESize >= 0);
  339. // Allocate space for the RLE bitmap.
  340. // This should be the exact size required for the RLE bitmap.
  341. // Add 8 bytes to handle the fact that GpMalloc may not return
  342. // a 64bit aligned allocation.
  343. void *RLEBits = GpMalloc((INT)(INT_PTR)(RLESize)+8);
  344. if(RLEBits == NULL) { FAIL(); } // Out of memory.
  345. // QWORD-align the result
  346. EpScanRecord *recordStart = MAKE_QWORD_ALIGNED(EpScanRecord *, RLEBits);
  347. // Scan through the dynamic array and add each record to the RLE bitmap
  348. // followed by its bits (pixels).
  349. // For native format pixels (opaque) use the EpAlphaBlender to
  350. // convert to native format.
  351. // Query for the number of records in the RunData
  352. INT nRecords = RunData.GetCount();
  353. EpScanRecord *rec = recordStart;
  354. ScanRecordTemp *pscTmp;
  355. // Store the rendering origin so we can modify it.
  356. // The graphics must be locked at the API.
  357. INT renderX, renderY;
  358. graphics->GetRenderingOrigin(&renderX, &renderY);
  359. // Set the rendering origin to the top left corner of the CachedBitmap
  360. // so that the dither pattern for the native pixels will match
  361. // the dither pattern for the semi-transparent pixels (rendered later
  362. // in DrawCachedBitmap).
  363. graphics->SetRenderingOrigin(0,0);
  364. // Make a 32bppPARGB->Native conversion blender.
  365. // This will be used for converting the 32bppPARGB
  366. // source data into the native pixel format (dstFormat)
  367. // of the destination.
  368. // For palettized modes, dstFormat is 32bppRGB
  369. EpAlphaBlender alphaBlender;
  370. alphaBlender.Initialize(
  371. EpScanTypeOpaque,
  372. dstFormat,
  373. PixelFormat32bppPARGB,
  374. graphics->Context,
  375. NULL,
  376. Buffers,
  377. TRUE,
  378. FALSE,
  379. 0
  380. );
  381. // For each record ...
  382. for(INT i=0; i<nRecords; i++)
  383. {
  384. // Make sure we don't overrun our buffer...
  385. ASSERT((INT_PTR)rec < (INT_PTR)recordStart + (INT_PTR)RLESize);
  386. // Copy the data into the destination record.
  387. pscTmp = &RunData[i];
  388. rec->X = pscTmp->x;
  389. rec->Y = pscTmp->y;
  390. rec->Width = rec->OrgWidth = pscTmp->width;
  391. // We should never store a transparent run.
  392. ASSERT(pscTmp->tsTransparent != Transparent);
  393. if(pscTmp->tsTransparent == Opaque)
  394. {
  395. // Use the native pixel format for the destination.
  396. rec->BlenderNum = 1;
  397. rec->ScanType = EpScanTypeOpaque;
  398. // Find the start of the new pixel run.
  399. VOID *dst = rec->GetColorBuffer();
  400. // Compute the number of bytes per pixel.
  401. INT pixelFormatSize = GetPixelFormatSize(dstFormat) >> 3;
  402. // This should perform a source over blend from 32bppPARGB
  403. // to the native format into the destination.
  404. // For CachedBitmaps, the dither origin is always the top
  405. // left corner of the CachedBitmap (i.e. 0, 0).
  406. // In 8bpp we dither down while rendering and get the correct
  407. // origin at that time.
  408. alphaBlender.Blend(
  409. dst,
  410. pscTmp->pStart,
  411. pscTmp->width,
  412. pscTmp->x,
  413. pscTmp->y,
  414. NULL
  415. );
  416. // Increment position to the next record.
  417. rec = rec->NextScanRecord(pixelFormatSize);
  418. }
  419. else
  420. {
  421. rec->BlenderNum = 0;
  422. rec->ScanType = EpScanTypeBlend;
  423. // Find the start of the new pixel run.
  424. VOID *dst = rec->GetColorBuffer();
  425. // Semi-Transparent pixels are stored in 32bpp PARGB, so
  426. // we can simply copy the pixels.
  427. GpMemcpy(dst, pscTmp->pStart, pscTmp->width*sizeof(ARGB));
  428. // Increment position to the next record.
  429. rec = rec->NextScanRecord(sizeof(ARGB));
  430. }
  431. }
  432. // Restore the rendering origin.
  433. graphics->SetRenderingOrigin(renderX, renderY);
  434. // Finally store the pointer to the RLE bits in the DeviceCachedBitmap
  435. DeviceCachedBitmap.Bits = RLEBits;
  436. DeviceCachedBitmap.RecordStart = recordStart;
  437. DeviceCachedBitmap.RecordEnd = rec;
  438. DeviceCachedBitmap.OpaqueFormat = dstFormat;
  439. DeviceCachedBitmap.SemiTransparentFormat = PixelFormat32bppPARGB;
  440. bitmap->UnlockBits(&bmpDataSrc);
  441. // Everything is golden - set Valid to TRUE
  442. // all the error paths early out with Valid set to FALSE
  443. SetValid(TRUE);
  444. }
  445. #undef FAIL
  446. GpCachedBitmap::~GpCachedBitmap()
  447. {
  448. // throw away the cached bitmap storage.
  449. GpFree(DeviceCachedBitmap.Bits);
  450. SetValid(FALSE); // so we don't use a deleted object
  451. }