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.

1126 lines
36 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999-2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Alpha-blender
  8. *
  9. * Abstract:
  10. *
  11. * A class which alpha-blends a source scanline in either sRGB or
  12. * sRGB64 format, to a destination of arbitrary format.
  13. *
  14. * Revision History:
  15. *
  16. * 01/03/2000 agodfrey
  17. * Created it.
  18. * 02/22/2001 agodfrey
  19. * Expanded it for different scan types (needed for ClearType).
  20. * Simplified the Initialize() parameters by adding a
  21. * DpContext parameter.
  22. *
  23. \**************************************************************************/
  24. #include "precomp.hpp"
  25. #include "scanoperationinternal.hpp"
  26. // !!![agodfrey] Hack:
  27. const ColorPalette*
  28. GetDefaultColorPalette(PixelFormatID pixfmt);
  29. inline UINT
  30. GetPixelFormatIndex(
  31. PixelFormatID pixfmt
  32. )
  33. {
  34. return pixfmt & 0xff;
  35. }
  36. // !!![agodfrey] Endhack
  37. // BLENDER_USE_DESTINATION and BLENDER_USE_SOURCE are used in the Src and
  38. // Dst fields of PipelineItem:
  39. // BLENDER_USE_SOURCE: Use the blend's original source
  40. // (i.e. the sRGB/sRGB64 scanbuffer)
  41. // BLENDER_USE_DESTINATION: Use the blend's final destination.
  42. // BLENDER_INVALID: Used in the debug build for assertions.
  43. #define BLENDER_USE_DESTINATION ((VOID *) 0)
  44. #define BLENDER_USE_SOURCE ((VOID *) 1)
  45. #define BLENDER_INVALID ((VOID *) 2)
  46. using namespace ScanOperation;
  47. /**************************************************************************\
  48. *
  49. * Special-case blend operations which blend directly to a given destination
  50. * format (with the source in 32BPP_PARGB).
  51. *
  52. * Notes:
  53. *
  54. * The 555/565 cases handle both dithering and non-dithering,
  55. * selected via OtherParams::DoingDither.
  56. *
  57. * We leave out PIXFMT_32BPP_ARGB and PIXFMT_64BPP_ARGB, since they're not
  58. * "ignore destination alpha" formats, so we'd need to AlphaDivide after
  59. * the blend.
  60. *
  61. \**************************************************************************/
  62. ScanOpFunc ScanOperation::BlendOpsLowQuality[PIXFMT_MAX] =
  63. {
  64. NULL, // PIXFMT_UNDEFINED
  65. NULL, // PIXFMT_1BPP_INDEXED
  66. NULL, // PIXFMT_4BPP_INDEXED
  67. NULL, // PIXFMT_8BPP_INDEXED
  68. NULL, // PIXFMT_16BPP_GRAYSCALE
  69. Dither_Blend_sRGB_555, // PIXFMT_16BPP_RGB555
  70. Dither_Blend_sRGB_565, // PIXFMT_16BPP_RGB565
  71. NULL, // PIXFMT_16BPP_ARGB1555
  72. Blend_sRGB_24, // PIXFMT_24BPP_RGB
  73. Blend_sRGB_sRGB, // PIXFMT_32BPP_RGB
  74. NULL, // PIXFMT_32BPP_ARGB
  75. Blend_sRGB_sRGB, // PIXFMT_32BPP_PARGB
  76. NULL, // PIXFMT_48BPP_RGB
  77. NULL, // PIXFMT_64BPP_ARGB
  78. NULL, // PIXFMT_64BPP_PARGB
  79. Blend_sRGB_24BGR // PIXFMT_24BPP_BGR
  80. };
  81. /**************************************************************************\
  82. *
  83. * Special-case gamma-corrected blend operations which blend directly to a
  84. * given destination format (with the source in 32BPP_PARGB).
  85. *
  86. * Notes:
  87. *
  88. * The 555/565 cases must handle both dithering and non-dithering,
  89. * selected via OtherParams::DoingDither.
  90. *
  91. * We leave out PIXFMT_32BPP_ARGB and PIXFMT_64BPP_ARGB, since they're not
  92. * "ignore destination alpha" formats, so we'd need to AlphaDivide after
  93. * the blend.
  94. *
  95. \**************************************************************************/
  96. ScanOpFunc ScanOperation::BlendOpsHighQuality[PIXFMT_MAX] =
  97. {
  98. NULL, // PIXFMT_UNDEFINED
  99. NULL, // PIXFMT_1BPP_INDEXED
  100. NULL, // PIXFMT_4BPP_INDEXED
  101. NULL, // PIXFMT_8BPP_INDEXED
  102. NULL, // PIXFMT_16BPP_GRAYSCALE
  103. BlendLinear_sRGB_555, // PIXFMT_16BPP_RGB555
  104. BlendLinear_sRGB_565, // PIXFMT_16BPP_RGB565
  105. NULL, // PIXFMT_16BPP_ARGB1555
  106. NULL, // PIXFMT_24BPP_RGB
  107. BlendLinear_sRGB_32RGB, // PIXFMT_32BPP_RGB
  108. NULL, // PIXFMT_32BPP_ARGB
  109. NULL, // PIXFMT_32BPP_PARGB
  110. NULL, // PIXFMT_48BPP_RGB
  111. NULL, // PIXFMT_64BPP_ARGB
  112. Blend_sRGB64_sRGB64, // PIXFMT_64BPP_PARGB
  113. NULL // PIXFMT_24BPP_BGR
  114. };
  115. /**************************************************************************\
  116. *
  117. * Operations which convert from the closest canonical format - either
  118. * 32BPP_ARGB or 64BPP_ARGB).
  119. *
  120. * This is specific to EpAlphaBlender. EpFormatConverter uses a different
  121. * table; some of the entries are different.
  122. *
  123. * The NULL entries for 32BPP_ARGB and 64_BPP_ARGB are used to indicate that no
  124. * conversion is necessary.
  125. *
  126. * These operations work on all processors.
  127. *
  128. * Notes:
  129. *
  130. * The 555/565 cases handle both dithering and non-dithering,
  131. * selected via OtherParams::DoingDither.
  132. *
  133. \**************************************************************************/
  134. ScanOpFunc ScanOperation::ABConvertFromCanonicalOps[PIXFMT_MAX] =
  135. {
  136. NULL, // PIXFMT_UNDEFINED
  137. NULL, // PIXFMT_1BPP_INDEXED
  138. NULL, // PIXFMT_4BPP_INDEXED
  139. HalftoneToScreen_sRGB_8_16, // PIXFMT_8BPP_INDEXED
  140. NULL, // PIXFMT_16BPP_GRAYSCALE
  141. Dither_sRGB_555, // PIXFMT_16BPP_RGB555
  142. Dither_sRGB_565, // PIXFMT_16BPP_RGB565
  143. Quantize_sRGB_1555, // PIXFMT_16BPP_ARGB1555
  144. Quantize_sRGB_24, // PIXFMT_24BPP_RGB
  145. Quantize_sRGB_32RGB, // PIXFMT_32BPP_RGB
  146. NULL, // PIXFMT_32BPP_ARGB
  147. AlphaMultiply_sRGB, // PIXFMT_32BPP_PARGB
  148. Quantize_sRGB64_48, // PIXFMT_48BPP_RGB
  149. NULL, // PIXFMT_64BPP_ARGB
  150. AlphaMultiply_sRGB64, // PIXFMT_64BPP_PARGB
  151. Quantize_sRGB_24BGR // PIXFMT_24BPP_BGR
  152. };
  153. // Builder: Holds the intermediate state and logic used to build the
  154. // blending pipeline.
  155. class EpAlphaBlender::Builder
  156. {
  157. public:
  158. Builder(
  159. PipelineItem *pipelinePtr,
  160. VOID **tempBuffers,
  161. GpCompositingMode compositingMode
  162. )
  163. {
  164. TempBuffers = tempBuffers;
  165. PipelinePtr = pipelinePtr;
  166. // At the start, the source and destination data are in external
  167. // buffers.
  168. CurrentDstBuffer = BLENDER_USE_DESTINATION;
  169. CurrentSrcBuffer = BLENDER_USE_SOURCE;
  170. #if DBG
  171. CompositingMode = compositingMode;
  172. if (compositingMode == CompositingModeSourceCopy)
  173. {
  174. // In SourceCopy mode, we never read from the destination -
  175. // we only write to it.
  176. CurrentDstBuffer = BLENDER_INVALID;
  177. }
  178. #endif
  179. // At the start, all 3 buffers are free. We'll use buffer 0 first.
  180. // The 'current' source and destination buffers are external buffers,
  181. // but we set CurrentDstIndex and CurrentSrcIndex in such a way that
  182. // the 'free buffer' logic works.
  183. FreeBufferIndex = 0;
  184. CurrentDstIndex = 1;
  185. CurrentSrcIndex = 2;
  186. }
  187. BOOL IsEmpty(
  188. EpAlphaBlender &blender
  189. )
  190. {
  191. return PipelinePtr == blender.Pipeline;
  192. }
  193. VOID End(
  194. EpAlphaBlender &blender
  195. )
  196. {
  197. // Check that we have at least one operation
  198. ASSERT(!IsEmpty(blender));
  199. // Check that we haven't overstepped the end of the pipeline space
  200. ASSERT(((PipelinePtr - blender.Pipeline) / sizeof(blender.Pipeline[0]))
  201. <= MAX_ITEMS);
  202. // Many of these cases will not have set the destination of the final
  203. // item in the pipeline correctly (it's hard for them to know that
  204. // they're doing the last item in the pipeline). So we explicitly set
  205. // it here.
  206. (PipelinePtr-1)->Dst = BLENDER_USE_DESTINATION;
  207. #if DBG
  208. // Make further member function calls hit an assertion.
  209. PipelinePtr = NULL;
  210. #endif
  211. }
  212. VOID
  213. AddConvertSource(
  214. ScanOperation::ScanOpFunc op
  215. )
  216. {
  217. // Check that we're not calling this when we shouldn't
  218. ASSERT(CurrentSrcBuffer != BLENDER_INVALID);
  219. // Choose the next temporary buffer
  220. INT nextIndex = FreeBufferIndex;
  221. VOID *nextBuffer = TempBuffers[nextIndex];
  222. // Add the operation
  223. AddOperation(op, CurrentSrcBuffer, nextBuffer);
  224. CurrentSrcBuffer = nextBuffer;
  225. // Swap the 'free' and 'current' indices.
  226. FreeBufferIndex = CurrentSrcIndex;
  227. CurrentSrcIndex = nextIndex;
  228. }
  229. VOID
  230. AddConvertDestination(
  231. ScanOperation::ScanOpFunc op
  232. )
  233. {
  234. // Check that we're not calling this when we shouldn't
  235. ASSERT(CompositingMode != CompositingModeSourceCopy);
  236. ASSERT(CurrentDstBuffer != BLENDER_INVALID);
  237. // Choose the next temporary buffer
  238. INT nextIndex = FreeBufferIndex;
  239. VOID *nextBuffer = TempBuffers[nextIndex];
  240. // Add the operation
  241. AddOperation(op, CurrentDstBuffer, nextBuffer);
  242. CurrentDstBuffer = nextBuffer;
  243. // Swap the 'free' and 'current' indices.
  244. FreeBufferIndex = CurrentDstIndex;
  245. CurrentDstIndex = nextIndex;
  246. }
  247. VOID
  248. AddBlend(
  249. ScanOperation::ScanOpFunc op,
  250. EpAlphaBlender &blender
  251. )
  252. {
  253. // Check that we're not calling this when we shouldn't
  254. ASSERT(CompositingMode != CompositingModeSourceCopy);
  255. ASSERT(CurrentSrcBuffer != BLENDER_INVALID);
  256. ASSERT(CurrentDstBuffer != BLENDER_INVALID);
  257. ASSERT(CurrentDstBuffer != BLENDER_USE_SOURCE);
  258. // If we're going to have to convert the source blend pixels, initialize
  259. // 'BlendingScan' to point to the temporary buffer in which the
  260. // converted pixels will end up. Otherwise, Blend() will have to
  261. // initialize 'BlendingScan'.
  262. if (CurrentSrcBuffer != BLENDER_USE_SOURCE)
  263. {
  264. blender.ConvertBlendingScan = TRUE;
  265. blender.OperationParameters.BlendingScan = CurrentSrcBuffer;
  266. }
  267. else
  268. {
  269. blender.ConvertBlendingScan = FALSE;
  270. }
  271. // The pipeline doesn't necessarily end with a WriteRMW operation
  272. // (or with one which contains it). So we must avoid blending from
  273. // one temporary buffer to another - the blend functions aren't
  274. // strictly ternary, and so we would end up leaving garbage values
  275. // in the target temporary buffer (whenever we blend a completely
  276. // transparent pixel).
  277. AddOperation(op, CurrentDstBuffer, CurrentDstBuffer);
  278. #if DBG
  279. // After this, we shouldn't call AddConvertSource or AddBlend again.
  280. CurrentSrcBuffer = BLENDER_INVALID;
  281. // And if this blend wasn't to a temporary buffer, this should be
  282. // the final operation in the pipeline. In particular, the caller
  283. // shouldn't try to add a WriteRMW operation after this.
  284. if (CurrentDstBuffer == BLENDER_USE_DESTINATION)
  285. {
  286. CurrentDstBuffer = BLENDER_INVALID;
  287. }
  288. #endif
  289. }
  290. protected:
  291. // AddOperation: Adds an operation to the pipeline.
  292. VOID
  293. AddOperation(
  294. ScanOperation::ScanOpFunc op,
  295. VOID *src,
  296. VOID *dst
  297. )
  298. {
  299. ASSERT(PipelinePtr != NULL);
  300. ASSERT(op != NULL);
  301. ASSERT(src != BLENDER_INVALID);
  302. ASSERT(dst != BLENDER_INVALID);
  303. *PipelinePtr++ = PipelineItem(op, src, dst);
  304. }
  305. PipelineItem *PipelinePtr; // Points to the space for the next item
  306. VOID **TempBuffers; // The 3 temporary scan-line buffers
  307. INT FreeBufferIndex; // The index of the next free scan-line buffer
  308. VOID *CurrentDstBuffer; // The buffer holding the most recently-converted
  309. VOID *CurrentSrcBuffer; // dst/src pixels.
  310. INT CurrentDstIndex; // The index of the scan-line buffer equal
  311. INT CurrentSrcIndex; // to CurrentDstBuffer/CurrentSrcBuffer (kinda)
  312. #if DBG
  313. GpCompositingMode CompositingMode;
  314. #endif
  315. };
  316. /**************************************************************************\
  317. *
  318. * Function Description:
  319. *
  320. * Initialize the alpha-blender object
  321. *
  322. * Arguments:
  323. *
  324. * scanType - The type of scan to output.
  325. * dstFormat - The pixel format of the destination. This shouldn't be
  326. * lower than 8bpp.
  327. * srcFormat - The pixel format of the source. This should be either
  328. * PIXFMT_32BPP_PARGB, or PIXFMT_64BPP_PARGB, except in
  329. * SourceCopy mode, in which it can be any legal
  330. * destination format.
  331. * context - The graphics context.
  332. * dstpal - The destination color palette, if the destination is
  333. * palettized. (Can be NULL, but we'll need a palette to
  334. * be supplied [via UpdatePalette()] some time before
  335. * Blend() is called.)
  336. * tempBuffers - An array of 3 pointers to temporary buffers, which
  337. * should be 64-bit aligned (for perf reasons),
  338. * and have enough space to hold a scan of 64bpp pixels.
  339. * dither16bpp - If TRUE, and the destination format is 16bpp: We should
  340. * dither to the destination.
  341. * useRMW - Use the RMW optimization.
  342. * compositingQuality - Specifies whether to do a high-quality
  343. * (gamma-corrected) blend. A gamma-corrected blend will
  344. * be used if this flag says so, or if the source or
  345. * destination are linear formats like PIXFMT_64BPP_PARGB.
  346. *
  347. * Notes:
  348. *
  349. * This code speaks of "canonical" formats - it means the two formats
  350. * PIXFMT_32BPP_ARGB and PIXFMT_64BPP_ARGB.
  351. *
  352. * !!! [agodfrey]: "canonical" is a confusing word. We should just say
  353. * "intermediate" format.
  354. *
  355. * This function may be called multiple times during the lifetime of an
  356. * EpAlphaBlender object.
  357. *
  358. * All error cases are flagged as ASSERTs, so there is no return code.
  359. *
  360. * Return Value:
  361. *
  362. * NONE
  363. *
  364. \**************************************************************************/
  365. VOID
  366. EpAlphaBlender::Initialize(
  367. EpScanType scanType,
  368. PixelFormatID dstFormat,
  369. PixelFormatID srcFormat,
  370. const DpContext *context,
  371. const ColorPalette *dstpal,
  372. VOID **tempBuffers,
  373. BOOL dither16bpp,
  374. BOOL useRMW,
  375. ARGB solidColor
  376. )
  377. {
  378. // Isolate all the references to 'context'. Later, we may want to solve
  379. // the 'batching across primitives' problem, and depending on how we do
  380. // it, we may not want the original context passed down to this function.
  381. const EpPaletteMap *paletteMap = context->PaletteMap;
  382. GpCompositingMode compositingMode = context->CompositingMode;
  383. GpCompositingQuality compositingQuality = context->CompositingQuality;
  384. UINT textContrast = context->TextContrast;
  385. // ClearType doesn't work with SourceCopy
  386. BOOL isClearType = (scanType == EpScanTypeCT || scanType == EpScanTypeCTSolidFill);
  387. if (isClearType)
  388. {
  389. ASSERT(compositingMode != CompositingModeSourceCopy);
  390. }
  391. ////////////////////////////// PRECONDITIONS ///////////////////////////////
  392. // We don't have Quantize/Halftone operations for pixel formats below 8bpp.
  393. // Calling code will handle <8bpp, if it wants to, by asking us to
  394. // draw to 8bpp, and using GDI to read/write to the <8bpp format.
  395. ASSERT(GetPixelFormatSize(dstFormat) >= 8);
  396. // The following destination formats are not supported
  397. ASSERT(IsSupportedPixelFormat(dstFormat));
  398. // This function currently only supports these two compositing modes.
  399. ASSERT(compositingMode == CompositingModeSourceCopy ||
  400. compositingMode == CompositingModeSourceOver);
  401. ////////////////////////////// INITIALIZATION //////////////////////////////
  402. // Lazy initialization for MMX-specific code.
  403. if (!Initialized)
  404. {
  405. // We only need to check CPUSpecificOps initialization the first
  406. // time this EpAlphaBlender is initialized. On subsequent calls,
  407. // we know that a call to CPUSpecificOps::Initialize() has already
  408. // completed.
  409. CPUSpecificOps::Initialize();
  410. Initialized = TRUE;
  411. }
  412. OperationParameters.TempBuffers[0]=tempBuffers[0];
  413. OperationParameters.TempBuffers[1]=tempBuffers[1];
  414. OperationParameters.TempBuffers[2]=tempBuffers[2];
  415. // Set SolidColor - only used for SolidFill scan types
  416. OperationParameters.SolidColor = solidColor;
  417. OperationParameters.TextContrast = textContrast;
  418. // The pipeline builder
  419. Builder builder(
  420. Pipeline,
  421. tempBuffers,
  422. compositingMode
  423. );
  424. INT dstfmtIndex = GetPixelFormatIndex(dstFormat);
  425. INT srcfmtIndex = GetPixelFormatIndex(srcFormat);
  426. BOOL dstExtended = IsExtendedPixelFormat(dstFormat);
  427. BOOL srcExtended = IsExtendedPixelFormat(srcFormat);
  428. OperationParameters.DoingDither = dither16bpp;
  429. // If the destination format doesn't have an alpha channel, we can make
  430. // a few optimizations. For example, we can avoid AlphaMultiply/AlphaDivide
  431. // in some cases.
  432. BOOL ignoreDstAlpha = !IsAlphaPixelFormat(dstFormat);
  433. // If the destination pixel format is an indexed color format,
  434. // get the color palette and palette map
  435. if (IsIndexedPixelFormat(dstFormat))
  436. {
  437. OperationParameters.Dstpal = OperationParameters.Srcpal =
  438. (dstpal ? dstpal : GetDefaultColorPalette(dstFormat));
  439. OperationParameters.PaletteMap = paletteMap;
  440. }
  441. // Process the 'compositingQuality' parameter
  442. BOOL highQuality = FALSE;
  443. switch (compositingQuality)
  444. {
  445. case CompositingQualityDefault:
  446. case CompositingQualityHighSpeed:
  447. case CompositingQualityAssumeLinear:
  448. break;
  449. case CompositingQualityHighQuality:
  450. case CompositingQualityGammaCorrected:
  451. highQuality = TRUE;
  452. break;
  453. default:
  454. RIP(("Unrecognized compositing quality: %d", compositingQuality));
  455. break;
  456. }
  457. // Work out whether our intermediate format (if we're doing SourceOver)
  458. // needs to be 32bpp or 64bpp.
  459. BOOL blendExtended = dstExtended || srcExtended || highQuality;
  460. if (isClearType)
  461. blendExtended = FALSE;
  462. // Decide on the 'convert from canonical' operation. (We do it now since
  463. // the logic is the same for all branches.)
  464. ScanOpFunc convertFromCanonical = ABConvertFromCanonicalOps[dstfmtIndex];
  465. switch (dstFormat)
  466. {
  467. case PIXFMT_8BPP_INDEXED:
  468. if (paletteMap && !paletteMap->IsVGAOnly())
  469. {
  470. convertFromCanonical = HalftoneToScreen_sRGB_8_216;
  471. }
  472. // If there is no palette map yet, we'll default to the 16-color
  473. // halftone function. Later on, in UpdatePalette(), we'll update this
  474. // function pointer if necessary. Ugh.
  475. break;
  476. case PIXFMT_32BPP_RGB:
  477. // ignoreDstAlpha should have been set to TRUE earlier.
  478. ASSERT(ignoreDstAlpha);
  479. // We can write garbage to the high byte, so we treat this
  480. // exactly as if the destination were ARGB. This avoids calling
  481. // Quantize_sRGB_32RGB and Convert_32RGB_sRGB.
  482. convertFromCanonical = NULL;
  483. dstFormat = PIXFMT_32BPP_ARGB;
  484. break;
  485. case PIXFMT_16BPP_RGB555:
  486. case PIXFMT_16BPP_RGB565:
  487. // The Dither_Blend_sRGB_555_MMX and Dither_Blend_sRGB_565_MMX
  488. // operations, unlike other blends, are not WriteRMW operations.
  489. // They sometimes write when a blend pixel is completely transparent.
  490. // So, we must not use a ReadRMW operation (otherwise we'd write garbage
  491. // to the destination.)
  492. if (OSInfo::HasMMX && !blendExtended && !isClearType)
  493. {
  494. useRMW = FALSE;
  495. }
  496. break;
  497. }
  498. /////////////////////////// SOURCECOPY / OPAQUE ////////////////////////////
  499. if ( (scanType == EpScanTypeOpaque)
  500. || (compositingMode == CompositingModeSourceCopy))
  501. {
  502. // (See bug #122441).
  503. //
  504. // We can now tell the difference between opaque input and general
  505. // SourceCopy. But I can't fix the bug right now. So, for now
  506. // we treat SourceCopy like the opaque case.
  507. //
  508. // This gives the wrong answer if the Graphics has SourceCopy mode set
  509. // and the user is drawing semitransparent pixels. Note that they need
  510. // to be doing this to a non-alpha surface to hit this case,
  511. // which is pretty dumb anyway.
  512. if (srcFormat == PIXFMT_32BPP_PARGB
  513. && ignoreDstAlpha
  514. && !dstExtended)
  515. {
  516. // At this point, the destination shouldn't be 32BPP_PARGB, because
  517. // we want that to be handled with a simple Copy_32 operation.
  518. // But that's okay - we shouldn't be here if the destination is
  519. // 32BPP_PARGB, because ignoreDstAlpha shouldn't be TRUE.
  520. ASSERT(dstFormat != PIXFMT_32BPP_PARGB);
  521. srcFormat = PIXFMT_32BPP_ARGB;
  522. }
  523. // If the formats are identical, just use a copy operation.
  524. if (srcFormat == dstFormat)
  525. {
  526. builder.AddConvertSource(CopyOps[dstfmtIndex]);
  527. goto PipelineDone;
  528. }
  529. // We don't check for other special case conversion operations for
  530. // SourceCopy, because:
  531. // 1) I'm lazy
  532. // 2) We don't have any at the moment
  533. // 3) If the source isn't in one of the canonical formats, we expect
  534. // that the destination will be the same format. Otherwise, it's
  535. // not a perf-important scenario, at least not right now.
  536. // Convert to the nearest canonical format, if necessary
  537. if (srcFormat != PIXFMT_32BPP_ARGB &&
  538. srcFormat != PIXFMT_64BPP_ARGB)
  539. {
  540. builder.AddConvertSource(ConvertIntoCanonicalOps[srcfmtIndex]);
  541. }
  542. // Convert to the other canonical format, if necessary
  543. if (srcExtended != dstExtended)
  544. {
  545. builder.AddConvertSource(
  546. srcExtended ?
  547. GammaConvert_sRGB64_sRGB :
  548. GammaConvert_sRGB_sRGB64);
  549. }
  550. // Convert to the destination format, if necessary
  551. if (convertFromCanonical)
  552. {
  553. builder.AddConvertSource(convertFromCanonical);
  554. }
  555. // At least one of these should have added an operation (since
  556. // the case where the source and destination formats are identical
  557. // was handled already).
  558. ASSERT(!builder.IsEmpty(*this));
  559. goto PipelineDone;
  560. }
  561. ////////////////////////// SOURCEOVER / CLEARTYPE //////////////////////////
  562. ASSERT( (scanType == EpScanTypeBlend)
  563. || isClearType);
  564. // The pseudocode is as follows:
  565. // * Handle ReadRMW
  566. // * Check for a special-case blend
  567. // * Convert source to blend format
  568. // * Convert destination to blend format
  569. // * Blend
  570. // * Convert to destination format
  571. // * WriteRMW
  572. // * Handle ReadRMW
  573. // We'll also decide which WriteRMW operation to use at the end.
  574. ScanOpFunc writeRMWfunc;
  575. ScanOpFunc readRMWfunc;
  576. writeRMWfunc = NULL;
  577. readRMWfunc = NULL;
  578. if (useRMW)
  579. {
  580. if (isClearType)
  581. {
  582. switch (GetPixelFormatSize(dstFormat))
  583. {
  584. case 16:
  585. if (scanType == EpScanTypeCT)
  586. {
  587. readRMWfunc = ReadRMW_16_CT_CARGB;
  588. writeRMWfunc = WriteRMW_16_CT_CARGB;
  589. }
  590. else
  591. {
  592. readRMWfunc = ReadRMW_16_CT_Solid;
  593. writeRMWfunc = WriteRMW_16_CT_Solid;
  594. }
  595. break;
  596. case 24:
  597. if (scanType == EpScanTypeCT)
  598. {
  599. readRMWfunc = ReadRMW_24_CT_CARGB;
  600. writeRMWfunc = WriteRMW_24_CT_CARGB;
  601. }
  602. else
  603. {
  604. readRMWfunc = ReadRMW_24_CT_Solid;
  605. writeRMWfunc = WriteRMW_24_CT_Solid;
  606. }
  607. break;
  608. }
  609. }
  610. else
  611. if (blendExtended)
  612. {
  613. switch (GetPixelFormatSize(dstFormat))
  614. {
  615. case 8:
  616. readRMWfunc = ReadRMW_8_sRGB64;
  617. writeRMWfunc = WriteRMW_8_sRGB64;
  618. break;
  619. case 16:
  620. // For special-case high quality blends to 16bpp formats, RMW has no perf
  621. // gain, and is simply overhead.
  622. // readRMWfunc = ReadRMW_16_sRGB64;
  623. // writeRMWfunc = WriteRMW_16_sRGB64;
  624. break;
  625. case 24:
  626. readRMWfunc = ReadRMW_24_sRGB64;
  627. writeRMWfunc = WriteRMW_24_sRGB64;
  628. break;
  629. case 32:
  630. // For special-case high quality blends to 32bpp formats, RMW has no perf
  631. // gain, and is simply overhead.
  632. // readRMWfunc = ReadRMW_32_sRGB64;
  633. // writeRMWfunc = WriteRMW_32_sRGB64;
  634. break;
  635. }
  636. }
  637. else
  638. {
  639. switch (GetPixelFormatSize(dstFormat))
  640. {
  641. case 8:
  642. readRMWfunc = ReadRMW_8_sRGB;
  643. writeRMWfunc = WriteRMW_8_sRGB;
  644. break;
  645. case 16:
  646. readRMWfunc = ReadRMW_16_sRGB;
  647. writeRMWfunc = WriteRMW_16_sRGB;
  648. break;
  649. case 24:
  650. readRMWfunc = ReadRMW_24_sRGB;
  651. writeRMWfunc = WriteRMW_24_sRGB;
  652. break;
  653. case 32:
  654. // For special-base blends to 32bpp formats, RMW has no perf
  655. // gain, and is simply overhead.
  656. // readRMWfunc = ReadRMW_32_sRGB;
  657. // writeRMWfunc = WriteRMW_32_sRGB;
  658. break;
  659. }
  660. }
  661. // We won't actually add the ReadRMW here. For example, if the source is
  662. // 32bpp and we want to do an extended blend, we need to convert
  663. // the source before doing the ReadRMW.
  664. //
  665. // However, we needed the logic here so that the special-case blend
  666. // code doesn't need to duplicate it.
  667. }
  668. // * Check for a special-case blend
  669. ScanOpFunc specialCaseBlend;
  670. specialCaseBlend = NULL;
  671. if (scanType == EpScanTypeBlend && !srcExtended)
  672. {
  673. if (blendExtended)
  674. {
  675. specialCaseBlend = BlendOpsHighQuality[dstfmtIndex];
  676. }
  677. else
  678. {
  679. specialCaseBlend = BlendOpsLowQuality[dstfmtIndex];
  680. }
  681. if (specialCaseBlend)
  682. {
  683. // If we're supposed to ReadRMW, do it now.
  684. if (readRMWfunc)
  685. {
  686. builder.AddConvertDestination(readRMWfunc);
  687. }
  688. // Dither_Blend_sRGB_555_MMX and Dither_Blend_sRGB_565_MMX
  689. // don't work with ReadRMW. Earlier code should have handled
  690. // it, so we'll just assert it here.
  691. ASSERT(!( ( (specialCaseBlend == Dither_Blend_sRGB_555_MMX)
  692. || (specialCaseBlend == Dither_Blend_sRGB_565_MMX)
  693. )
  694. && (useRMW)));
  695. builder.AddBlend(specialCaseBlend, *this);
  696. goto PipelineDone;
  697. }
  698. }
  699. // * Convert source to blend format
  700. // We currently only support source data other than 32BPP_PARGB and
  701. // 64BPP_PARGB for the SourceCopy case.
  702. ASSERT( (srcFormat == PIXFMT_32BPP_PARGB)
  703. || (srcFormat == PIXFMT_64BPP_PARGB));
  704. if (blendExtended && !srcExtended)
  705. {
  706. // Unfortunately, the source is premultiplied and we need to gamma
  707. // convert it. We must divide by the alpha first, and remultiply
  708. // afterwards.
  709. builder.AddConvertSource(AlphaDivide_sRGB);
  710. builder.AddConvertSource(GammaConvert_sRGB_sRGB64);
  711. builder.AddConvertSource(AlphaMultiply_sRGB64);
  712. }
  713. // * Handle ReadRMW (continued)
  714. if (readRMWfunc)
  715. {
  716. builder.AddConvertDestination(readRMWfunc);
  717. }
  718. // * Convert destination to blend format
  719. // Skip this if it's already in the blend format
  720. if ( (blendExtended && dstFormat != PIXFMT_64BPP_PARGB)
  721. || (!blendExtended && dstFormat != PIXFMT_32BPP_PARGB))
  722. {
  723. // Convert to the nearest canonical format, if necessary
  724. if (dstFormat != PIXFMT_32BPP_ARGB &&
  725. dstFormat != PIXFMT_64BPP_ARGB)
  726. {
  727. builder.AddConvertDestination(ConvertIntoCanonicalOps[dstfmtIndex]);
  728. }
  729. // Convert to sRGB64, if necessary
  730. if (!srcExtended && blendExtended)
  731. {
  732. builder.AddConvertDestination(GammaConvert_sRGB_sRGB64);
  733. }
  734. // Convert to the premultiplied version, if necessary
  735. if (!ignoreDstAlpha)
  736. {
  737. builder.AddConvertDestination(
  738. blendExtended ?
  739. AlphaMultiply_sRGB64 :
  740. AlphaMultiply_sRGB);
  741. }
  742. }
  743. // * Blend
  744. if (scanType == EpScanTypeCT)
  745. {
  746. builder.AddBlend(CTBlendCARGB, *this);
  747. }
  748. else if (scanType == EpScanTypeCTSolidFill)
  749. {
  750. builder.AddBlend(CTBlendSolid, *this);
  751. }
  752. else
  753. {
  754. builder.AddBlend(
  755. blendExtended ?
  756. BlendOpsHighQuality[GetPixelFormatIndex(PIXFMT_64BPP_PARGB)]:
  757. BlendOpsLowQuality[GetPixelFormatIndex(PIXFMT_32BPP_PARGB)],
  758. *this);
  759. }
  760. // * Convert to destination format
  761. // Skip this if it's already in the destination format
  762. if ( (blendExtended && dstFormat != PIXFMT_64BPP_PARGB)
  763. || (!blendExtended && dstFormat != PIXFMT_32BPP_PARGB))
  764. {
  765. // Convert to the nearest nonpremultiplied, if necessary
  766. if (!ignoreDstAlpha)
  767. {
  768. builder.AddConvertDestination(
  769. blendExtended ?
  770. AlphaDivide_sRGB64 :
  771. AlphaDivide_sRGB);
  772. }
  773. // Convert to the other canonical format, if necessary
  774. if (blendExtended != dstExtended)
  775. {
  776. builder.AddConvertDestination(
  777. blendExtended ?
  778. GammaConvert_sRGB64_sRGB :
  779. GammaConvert_sRGB_sRGB64);
  780. }
  781. // Convert to the destination format, if necessary
  782. if (convertFromCanonical)
  783. {
  784. builder.AddConvertDestination(convertFromCanonical);
  785. }
  786. }
  787. // * WriteRMW
  788. if (writeRMWfunc)
  789. {
  790. builder.AddConvertDestination(writeRMWfunc);
  791. }
  792. PipelineDone:
  793. builder.End(*this);
  794. }
  795. /**************************************************************************\
  796. *
  797. * Function Description:
  798. *
  799. * Blend source pixels to the given destination.
  800. *
  801. * Arguments:
  802. *
  803. * dst - The destination buffer
  804. * src - The source pixels to blend
  805. * width - The number of pixels in the source/destination buffers
  806. * dither_x - The x and y offsets of the destination scanline into the
  807. * dither_y - halftone or dither matrix (implicit mod the matrix size).
  808. * ctBuffer - The ClearType coverage buffer, or NULL for non-ClearType
  809. * scan types.
  810. *
  811. * Return Value:
  812. *
  813. * NONE
  814. *
  815. \**************************************************************************/
  816. VOID
  817. EpAlphaBlender::Blend(
  818. VOID *dst,
  819. VOID *src,
  820. UINT width,
  821. INT dither_x,
  822. INT dither_y,
  823. BYTE *ctBuffer
  824. )
  825. {
  826. if (!width)
  827. {
  828. return;
  829. }
  830. // If ConvertBlendingScan is TRUE, then Initialize() will already
  831. // have set BlendingScan to point to one of the temporary buffers.
  832. if (!ConvertBlendingScan)
  833. {
  834. OperationParameters.BlendingScan = src;
  835. }
  836. OperationParameters.CTBuffer = ctBuffer;
  837. OperationParameters.X = dither_x;
  838. OperationParameters.Y = dither_y;
  839. PipelineItem *pipelinePtr = &Pipeline[0];
  840. const VOID *currentSrc;
  841. VOID *currentDst;
  842. BOOL finished = FALSE;
  843. do
  844. {
  845. currentSrc = pipelinePtr->Src;
  846. currentDst = pipelinePtr->Dst;
  847. // We should never write to the original source, because we don't
  848. // control that memory.
  849. ASSERT (currentDst != BLENDER_USE_SOURCE);
  850. // Translate BLENDER_USE_SOURCE and BLENDER_USE_DESTINATION
  851. if (currentSrc == BLENDER_USE_SOURCE)
  852. {
  853. currentSrc = src;
  854. }
  855. if (currentSrc == BLENDER_USE_DESTINATION)
  856. {
  857. currentSrc = dst;
  858. }
  859. if (currentDst == BLENDER_USE_DESTINATION)
  860. {
  861. currentDst = dst;
  862. finished = TRUE;
  863. }
  864. pipelinePtr->Op(currentDst, currentSrc, width, &OperationParameters);
  865. pipelinePtr++;
  866. } while (!finished);
  867. }
  868. /**************************************************************************\
  869. *
  870. * Function Description:
  871. *
  872. * Update the palette/palette map.
  873. *
  874. * Arguments:
  875. *
  876. * dstpal - The destination color palette.
  877. * paletteMap - The palette map for the destination.
  878. *
  879. * Notes:
  880. *
  881. * Return Value:
  882. *
  883. * NONE
  884. *
  885. \**************************************************************************/
  886. VOID
  887. EpAlphaBlender::UpdatePalette(
  888. const ColorPalette *dstpal,
  889. const EpPaletteMap *paletteMap
  890. )
  891. {
  892. ASSERT(dstpal && paletteMap);
  893. BOOL wasVGAOnly = (!OperationParameters.PaletteMap) ||
  894. (OperationParameters.PaletteMap->IsVGAOnly());
  895. OperationParameters.Srcpal = OperationParameters.Dstpal = dstpal;
  896. OperationParameters.PaletteMap = paletteMap;
  897. // Detect whether we need to change the halftone function.
  898. if (wasVGAOnly != paletteMap->IsVGAOnly())
  899. {
  900. ScanOpFunc before, after;
  901. if (wasVGAOnly)
  902. {
  903. before = HalftoneToScreen_sRGB_8_16;
  904. after = HalftoneToScreen_sRGB_8_216;
  905. }
  906. else
  907. {
  908. before = HalftoneToScreen_sRGB_8_216;
  909. after = HalftoneToScreen_sRGB_8_16;
  910. }
  911. // Search the pipeline for the 'before' function, and replace it with
  912. // the 'after' function.
  913. PipelineItem *pipelinePtr = Pipeline;
  914. while (1)
  915. {
  916. if (pipelinePtr->Op == before)
  917. {
  918. pipelinePtr->Op = after;
  919. }
  920. if (pipelinePtr->Dst == BLENDER_USE_DESTINATION)
  921. {
  922. break;
  923. }
  924. pipelinePtr++;
  925. }
  926. }
  927. }