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.

687 lines
19 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: stretch.c
  3. *
  4. * Copyright (c) 1993-1995 Microsoft Corporation
  5. \**************************************************************************/
  6. #include "precomp.h"
  7. #define STRETCH_MAX_EXTENT 32767
  8. typedef DWORDLONG ULONGLONG;
  9. /******************************Public*Routine******************************\
  10. *
  11. * Routine Name
  12. *
  13. * vDirectStretch8Narrow
  14. *
  15. * Routine Description:
  16. *
  17. * Stretch blt 8->8 when the width is 7 or less
  18. *
  19. * Arguments:
  20. *
  21. * pStrBlt - contains all params for blt
  22. *
  23. * Return Value:
  24. *
  25. * VOID
  26. *
  27. \**************************************************************************/
  28. VOID vDirectStretch8Narrow(
  29. STR_BLT* pStrBlt)
  30. {
  31. BYTE* pjSrc;
  32. BYTE* pjDstEnd;
  33. ULONG ulDst;
  34. ULONG xAccum;
  35. ULONG xTmp;
  36. ULONG yTmp;
  37. LONG xDst = pStrBlt->XDstStart;
  38. LONG xSrc = pStrBlt->XSrcStart;
  39. BYTE* pjSrcScan = pStrBlt->pjSrcScan + xSrc;
  40. BYTE* pjDst = pStrBlt->pjDstScan + xDst;
  41. LONG yCount = pStrBlt->YDstCount;
  42. LONG WidthX = pStrBlt->XDstEnd - xDst;
  43. ULONG xInt = pStrBlt->ulXDstToSrcIntCeil;
  44. ULONG xFrac = pStrBlt->ulXDstToSrcFracCeil;
  45. ULONG yAccum = pStrBlt->ulYFracAccumulator;
  46. ULONG yFrac = pStrBlt->ulYDstToSrcFracCeil;
  47. LONG lDstStride = pStrBlt->lDeltaDst - WidthX;
  48. ULONG yInt = 0;
  49. yInt = pStrBlt->lDeltaSrc * pStrBlt->ulYDstToSrcIntCeil;
  50. //
  51. // Narrow blt
  52. //
  53. do {
  54. ULONG yTmp = yAccum + yFrac;
  55. BYTE jSrc0;
  56. BYTE* pjDstEndNarrow = pjDst + WidthX;
  57. pjSrc = pjSrcScan;
  58. xAccum = pStrBlt->ulXFracAccumulator;
  59. do {
  60. jSrc0 = *pjSrc;
  61. xTmp = xAccum + xFrac;
  62. pjSrc = pjSrc + xInt + (xTmp < xAccum);
  63. *pjDst++ = jSrc0;
  64. xAccum = xTmp;
  65. } while (pjDst != pjDstEndNarrow);
  66. pjSrcScan += yInt;
  67. if (yTmp < yAccum)
  68. {
  69. pjSrcScan += pStrBlt->lDeltaSrc;
  70. }
  71. yAccum = yTmp;
  72. pjDst += lDstStride;
  73. } while (--yCount);
  74. }
  75. /******************************Public*Routine******************************\
  76. *
  77. * Routine Description:
  78. *
  79. * StretchBlt using integer math. Must be from one surface to another
  80. * surface of the same format.
  81. *
  82. * Arguments:
  83. *
  84. * ppdev - PDEV for device
  85. * pvDst - Pointer to start of dst bitmap
  86. * lDeltaDst - Bytes from start of dst scan line to start of next
  87. * DstCx - Width of Dst Bitmap in pixels
  88. * DstCy - Height of Dst Bitmap in pixels
  89. * prclDst - Pointer to rectangle of Dst extents
  90. * pvSrc - Pointer to start of Src bitmap
  91. * lDeltaSrc - Bytes from start of Src scan line to start of next
  92. * SrcCx - Width of Src Bitmap in pixels
  93. * SrcCy - Height of Src Bitmap in pixels
  94. * prclSrc - Pointer to rectangle of Src extents
  95. * prclSClip - Clip Dest to this rect
  96. *
  97. * Return Value:
  98. *
  99. * Status
  100. *
  101. \**************************************************************************/
  102. BOOL bStretchDIB(
  103. PDEV* ppdev,
  104. VOID* pvDst,
  105. LONG lDeltaDst,
  106. RECTL* prclDst,
  107. VOID* pvSrc,
  108. LONG lDeltaSrc,
  109. RECTL* prclSrc,
  110. RECTL* prclClip)
  111. {
  112. STR_BLT StrBlt;
  113. ULONG XSrcToDstIntFloor;
  114. ULONG XSrcToDstFracFloor;
  115. ULONG ulXDstToSrcIntCeil;
  116. ULONG ulXDstToSrcFracCeil;
  117. ULONG YSrcToDstIntFloor;
  118. ULONG YSrcToDstFracFloor;
  119. ULONG ulYDstToSrcIntCeil;
  120. ULONG ulYDstToSrcFracCeil;
  121. LONG SrcIntScan;
  122. LONG DstDeltaScanEnd;
  123. ULONG ulXFracAccumulator;
  124. ULONG ulYFracAccumulator;
  125. LONG LeftClipDistance;
  126. LONG TopClipDistance;
  127. BOOL bStretch;
  128. union {
  129. LARGE_INTEGER large;
  130. ULONGLONG li;
  131. } liInit;
  132. PFN_DIRSTRETCH pfnStr;
  133. //
  134. // Calculate exclusive start and end points:
  135. //
  136. LONG WidthDst = prclDst->right - prclDst->left;
  137. LONG HeightDst = prclDst->bottom - prclDst->top;
  138. LONG WidthSrc = prclSrc->right - prclSrc->left;
  139. LONG HeightSrc = prclSrc->bottom - prclSrc->top;
  140. LONG XSrcStart = prclSrc->left;
  141. LONG XSrcEnd = prclSrc->right;
  142. LONG XDstStart = prclDst->left;
  143. LONG XDstEnd = prclDst->right;
  144. LONG YSrcStart = prclSrc->top;
  145. LONG YSrcEnd = prclSrc->bottom;
  146. LONG YDstStart = prclDst->top;
  147. LONG YDstEnd = prclDst->bottom;
  148. //
  149. // Validate parameters:
  150. //
  151. ASSERTDD(pvDst != (VOID*)NULL, "Bad destination bitmap pointer");
  152. ASSERTDD(pvSrc != (VOID*)NULL, "Bad source bitmap pointer");
  153. ASSERTDD(prclDst != (RECTL*)NULL, "Bad destination rectangle");
  154. ASSERTDD(prclSrc != (RECTL*)NULL, "Bad source rectangle");
  155. ASSERTDD((WidthDst > 0) && (HeightDst > 0) &&
  156. (WidthSrc > 0) && (HeightSrc > 0),
  157. "Can't do mirroring or empty rectangles here");
  158. ASSERTDD((WidthDst <= STRETCH_MAX_EXTENT) &&
  159. (HeightDst <= STRETCH_MAX_EXTENT) &&
  160. (WidthSrc <= STRETCH_MAX_EXTENT) &&
  161. (HeightSrc <= STRETCH_MAX_EXTENT), "Stretch exceeds limits");
  162. ASSERTDD(prclClip != NULL, "Bad clip rectangle");
  163. //
  164. // Calculate X Dst to Src mapping
  165. //
  166. //
  167. // dst->src = ( CEIL( (2k*WidthSrc)/WidthDst) ) / 2k
  168. //
  169. // = ( FLOOR( (2k*WidthSrc -1) / WidthDst) + 1) / 2k
  170. //
  171. // where 2k = 2 ^ 32
  172. //
  173. {
  174. ULONGLONG liWidthSrc;
  175. ULONGLONG liQuo;
  176. ULONG ulTemp;
  177. //
  178. // Work around a compiler bug dealing with the assignment
  179. // 'liHeightSrc = (((LONGLONG)HeightSrc) << 32) - 1':
  180. //
  181. liInit.large.LowPart = (ULONG) -1;
  182. liInit.large.HighPart = WidthSrc - 1;
  183. liWidthSrc = liInit.li;
  184. liQuo = liWidthSrc / (ULONGLONG) WidthDst;
  185. ulXDstToSrcIntCeil = (ULONG)(liQuo >> 32);
  186. ulXDstToSrcFracCeil = (ULONG)liQuo;
  187. //
  188. // Now add 1, use fake carry:
  189. //
  190. ulTemp = ulXDstToSrcFracCeil + 1;
  191. ulXDstToSrcIntCeil += (ulTemp < ulXDstToSrcFracCeil);
  192. ulXDstToSrcFracCeil = ulTemp;
  193. }
  194. //
  195. // Calculate Y Dst to Src mapping
  196. //
  197. //
  198. // dst->src = ( CEIL( (2k*HeightSrc)/HeightDst) ) / 2k
  199. //
  200. // = ( FLOOR( (2k*HeightSrc -1) / HeightDst) + 1) / 2k
  201. //
  202. // where 2k = 2 ^ 32
  203. //
  204. {
  205. ULONGLONG liHeightSrc;
  206. ULONGLONG liQuo;
  207. ULONG ulTemp;
  208. //
  209. // Work around a compiler bug dealing with the assignment
  210. // 'liHeightSrc = (((LONGLONG)HeightSrc) << 32) - 1':
  211. //
  212. liInit.large.LowPart = (ULONG) -1;
  213. liInit.large.HighPart = HeightSrc - 1;
  214. liHeightSrc = liInit.li;
  215. liQuo = liHeightSrc / (ULONGLONG) HeightDst;
  216. ulYDstToSrcIntCeil = (ULONG)(liQuo >> 32);
  217. ulYDstToSrcFracCeil = (ULONG)liQuo;
  218. //
  219. // Now add 1, use fake carry:
  220. //
  221. ulTemp = ulYDstToSrcFracCeil + 1;
  222. ulYDstToSrcIntCeil += (ulTemp < ulYDstToSrcFracCeil);
  223. ulYDstToSrcFracCeil = ulTemp;
  224. }
  225. //
  226. // Now clip Dst in X, and/or calc src clipping effect on dst
  227. //
  228. // adjust left and right edges if needed, record
  229. // distance adjusted for fixing the src
  230. //
  231. if (XDstStart < prclClip->left)
  232. {
  233. XDstStart = prclClip->left;
  234. }
  235. if (XDstEnd > prclClip->right)
  236. {
  237. XDstEnd = prclClip->right;
  238. }
  239. //
  240. // Check for totally clipped out destination:
  241. //
  242. if (XDstEnd <= XDstStart)
  243. {
  244. return(TRUE);
  245. }
  246. LeftClipDistance = XDstStart - prclDst->left;
  247. {
  248. ULONG ulTempInt;
  249. ULONG ulTempFrac;
  250. //
  251. // Calculate displacement for .5 in destination and add:
  252. //
  253. ulTempFrac = (ulXDstToSrcFracCeil >> 1) | (ulXDstToSrcIntCeil << 31);
  254. ulTempInt = (ulXDstToSrcIntCeil >> 1);
  255. XSrcStart += ulTempInt;
  256. ulXFracAccumulator = ulTempFrac;
  257. if (LeftClipDistance != 0)
  258. {
  259. ULONGLONG ullFraction;
  260. ULONG ulTmp;
  261. ullFraction = UInt32x32To64(ulXDstToSrcFracCeil, LeftClipDistance);
  262. ulTmp = ulXFracAccumulator;
  263. ulXFracAccumulator += (ULONG) (ullFraction);
  264. if (ulXFracAccumulator < ulTmp)
  265. XSrcStart++;
  266. XSrcStart += (ulXDstToSrcIntCeil * LeftClipDistance)
  267. + (ULONG) (ullFraction >> 32);
  268. }
  269. }
  270. //
  271. // Now clip Dst in Y, and/or calc src clipping effect on dst
  272. //
  273. // adjust top and bottom edges if needed, record
  274. // distance adjusted for fixing the src
  275. //
  276. if (YDstStart < prclClip->top)
  277. {
  278. YDstStart = prclClip->top;
  279. }
  280. if (YDstEnd > prclClip->bottom)
  281. {
  282. YDstEnd = prclClip->bottom;
  283. }
  284. //
  285. // Check for totally clipped out destination:
  286. //
  287. if (YDstEnd <= YDstStart)
  288. {
  289. return(TRUE);
  290. }
  291. TopClipDistance = YDstStart - prclDst->top;
  292. {
  293. ULONG ulTempInt;
  294. ULONG ulTempFrac;
  295. //
  296. // Calculate displacement for .5 in destination and add:
  297. //
  298. ulTempFrac = (ulYDstToSrcFracCeil >> 1) | (ulYDstToSrcIntCeil << 31);
  299. ulTempInt = ulYDstToSrcIntCeil >> 1;
  300. YSrcStart += (LONG)ulTempInt;
  301. ulYFracAccumulator = ulTempFrac;
  302. if (TopClipDistance != 0)
  303. {
  304. ULONGLONG ullFraction;
  305. ULONG ulTmp;
  306. ullFraction = UInt32x32To64(ulYDstToSrcFracCeil, TopClipDistance);
  307. ulTmp = ulYFracAccumulator;
  308. ulYFracAccumulator += (ULONG) (ullFraction);
  309. if (ulYFracAccumulator < ulTmp)
  310. YSrcStart++;
  311. YSrcStart += (ulYDstToSrcIntCeil * TopClipDistance)
  312. + (ULONG) (ullFraction >> 32);
  313. }
  314. }
  315. //
  316. // Warm up the hardware if doing an expanding stretch in 'y':
  317. //
  318. bStretch = (HeightDst > HeightSrc);
  319. if (bStretch)
  320. {
  321. BYTE* pjBase = ppdev->pjBase;
  322. LONG x;
  323. //
  324. // Set up the left and right blt edges, since they never change
  325. // during the StretchBlt
  326. //
  327. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  328. CP_FG_ROP(ppdev, pjBase, R3_SRCCOPY);
  329. CP_SRC_WRAP(ppdev, pjBase, NO_PATTERN_WRAP);
  330. CP_SRC_Y_OFFSET(ppdev, pjBase, (lDeltaDst - 1));
  331. CP_DST_Y_OFFSET(ppdev, pjBase, (lDeltaDst - 1));
  332. }
  333. //
  334. // Fill out blt structure, then call format-specific stretch code
  335. //
  336. StrBlt.ppdev = ppdev;
  337. StrBlt.XDstEnd = XDstEnd;
  338. StrBlt.YDstStart = YDstStart;
  339. StrBlt.YDstCount = YDstEnd - YDstStart;
  340. if (StrBlt.YDstCount > 0)
  341. {
  342. //
  343. // Caclulate starting scan line address. Since the inner loop
  344. // routines are format dependent, they must add XDstStart/XSrcStart
  345. // to pjDstScan/pjSrcScan to get the actual starting pixel address.
  346. //
  347. StrBlt.pjSrcScan = (BYTE*) pvSrc + (YSrcStart * lDeltaSrc);
  348. StrBlt.pjDstScan = (BYTE*) pvDst + (YDstStart * lDeltaDst);
  349. StrBlt.lDeltaSrc = lDeltaSrc;
  350. StrBlt.XSrcStart = XSrcStart;
  351. StrBlt.XDstStart = XDstStart;
  352. StrBlt.lDeltaDst = lDeltaDst;
  353. StrBlt.ulXDstToSrcIntCeil = ulXDstToSrcIntCeil;
  354. StrBlt.ulXDstToSrcFracCeil = ulXDstToSrcFracCeil;
  355. StrBlt.ulYDstToSrcIntCeil = ulYDstToSrcIntCeil;
  356. StrBlt.ulYDstToSrcFracCeil = ulYDstToSrcFracCeil;
  357. StrBlt.ulXFracAccumulator = ulXFracAccumulator;
  358. StrBlt.ulYFracAccumulator = ulYFracAccumulator;
  359. if (ppdev->iBitmapFormat == BMF_8BPP)
  360. {
  361. if ((XDstEnd - XDstStart) < 7)
  362. pfnStr = vDirectStretch8Narrow;
  363. else
  364. pfnStr = vDirectStretch8;
  365. }
  366. else
  367. {
  368. ASSERTDD(ppdev->iBitmapFormat == BMF_16BPP,
  369. "Only handle stretches at 8 and 16bpp");
  370. pfnStr = vDirectStretch16;
  371. }
  372. (*pfnStr)(&StrBlt);
  373. }
  374. return(TRUE);
  375. }
  376. /******************************Public*Routine******************************\
  377. * BOOL bBankedStretch
  378. *
  379. \**************************************************************************/
  380. BOOL bBankedStretch(
  381. PDEV* ppdev,
  382. VOID* pvDst,
  383. LONG lDeltaDst,
  384. RECTL* prclDst,
  385. VOID* pvSrc,
  386. LONG lDeltaSrc,
  387. RECTL* prclSrc,
  388. RECTL* prclClip)
  389. {
  390. BANK bnk;
  391. BOOL b;
  392. RECTL rclDst;
  393. b = TRUE;
  394. if (bIntersect(prclDst, prclClip, &rclDst))
  395. {
  396. vBankStart(ppdev, &rclDst, NULL, &bnk);
  397. do {
  398. b &= bStretchDIB(ppdev,
  399. bnk.pso->pvScan0,
  400. lDeltaDst,
  401. prclDst,
  402. pvSrc,
  403. lDeltaSrc,
  404. prclSrc,
  405. &bnk.pco->rclBounds);
  406. } while (bBankEnum(&bnk));
  407. }
  408. return(b);
  409. }
  410. /******************************Public*Routine******************************\
  411. * BOOL DrvStretchBlt
  412. *
  413. \**************************************************************************/
  414. BOOL DrvStretchBlt(
  415. SURFOBJ* psoDst,
  416. SURFOBJ* psoSrc,
  417. SURFOBJ* psoMsk,
  418. CLIPOBJ* pco,
  419. XLATEOBJ* pxlo,
  420. COLORADJUSTMENT* pca,
  421. POINTL* pptlHTOrg,
  422. RECTL* prclDst,
  423. RECTL* prclSrc,
  424. POINTL* pptlMsk,
  425. ULONG iMode)
  426. {
  427. DSURF* pdsurfSrc;
  428. DSURF* pdsurfDst;
  429. PDEV* ppdev;
  430. OH* poh;
  431. // !!! What about sparse-space Alpha?
  432. // GDI guarantees us that for a StretchBlt the destination surface
  433. // will always be a device surface, and not a DIB:
  434. ppdev = (PDEV*) psoDst->dhpdev;
  435. // It's quicker for GDI to do a StretchBlt when the source surface
  436. // is not a device-managed surface, because then it can directly
  437. // read the source bits without having to allocate a temporary
  438. // buffer and call DrvCopyBits to get a copy that it can use.
  439. //
  440. // So if the source is one of our off-screen DFBs, we'll immediately
  441. // and permanently convert it to a DIB:
  442. if (psoSrc->iType == STYPE_DEVBITMAP)
  443. {
  444. pdsurfSrc = (DSURF*) psoSrc->dhsurf;
  445. if (pdsurfSrc->dt == DT_SCREEN)
  446. {
  447. if (!pohMoveOffscreenDfbToDib(ppdev, pdsurfSrc->poh))
  448. return(FALSE);
  449. }
  450. ASSERTDD(pdsurfSrc->dt == DT_DIB, "Can only handle DIB DFBs here");
  451. psoSrc = pdsurfSrc->pso;
  452. }
  453. pdsurfDst = (DSURF*) psoDst->dhsurf;
  454. if (pdsurfDst->dt == DT_DIB)
  455. {
  456. // The destination was a device bitmap that we just converted
  457. // to a DIB:
  458. psoDst = pdsurfDst->pso;
  459. goto Punt_It;
  460. }
  461. poh = pdsurfDst->poh;
  462. ppdev->xOffset = poh->x;
  463. ppdev->yOffset = poh->y;
  464. ppdev->xyOffset = (ppdev->cBpp * ppdev->xOffset) +
  465. (ppdev->yOffset * ppdev->lDelta);
  466. {
  467. RECTL rclClip;
  468. RECTL* prclClip;
  469. ULONG cxDst;
  470. ULONG cyDst;
  471. ULONG cxSrc;
  472. ULONG cySrc;
  473. BOOL bMore;
  474. CLIPENUM ce;
  475. LONG c;
  476. LONG i;
  477. if ((psoSrc->iType == STYPE_BITMAP) &&
  478. (psoMsk == NULL) &&
  479. ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) &&
  480. ((psoSrc->iBitmapFormat == ppdev->iBitmapFormat)) &&
  481. (ppdev->iBitmapFormat != BMF_24BPP))
  482. {
  483. cxDst = prclDst->right - prclDst->left;
  484. cyDst = prclDst->bottom - prclDst->top;
  485. cxSrc = prclSrc->right - prclSrc->left;
  486. cySrc = prclSrc->bottom - prclSrc->top;
  487. // Our 'bStretchDIB' routine requires that the stretch be
  488. // non-inverting, within a certain size, to have no source
  489. // clipping, and to have no empty rectangles (the latter is the
  490. // reason for the '- 1' on the unsigned compare here):
  491. if (((cxSrc - 1) < STRETCH_MAX_EXTENT) &&
  492. ((cySrc - 1) < STRETCH_MAX_EXTENT) &&
  493. ((cxDst - 1) < STRETCH_MAX_EXTENT) &&
  494. ((cyDst - 1) < STRETCH_MAX_EXTENT) &&
  495. (prclSrc->left >= 0) &&
  496. (prclSrc->top >= 0) &&
  497. (prclSrc->right <= psoSrc->sizlBitmap.cx) &&
  498. (prclSrc->bottom <= psoSrc->sizlBitmap.cy))
  499. {
  500. // Our snazzy routine only does COLORONCOLOR. But for
  501. // stretching blts, BLACKONWHITE and WHITEONBLACK are also
  502. // equivalent to COLORONCOLOR:
  503. if ((iMode == COLORONCOLOR) ||
  504. ((iMode < COLORONCOLOR) && (cxSrc <= cxDst) && (cySrc <= cyDst)))
  505. {
  506. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  507. {
  508. rclClip.left = LONG_MIN;
  509. rclClip.top = LONG_MIN;
  510. rclClip.right = LONG_MAX;
  511. rclClip.bottom = LONG_MAX;
  512. prclClip = &rclClip;
  513. StretchSingleClipRect:
  514. if (bBankedStretch(ppdev,
  515. NULL,
  516. ppdev->lDelta,
  517. prclDst,
  518. psoSrc->pvScan0,
  519. psoSrc->lDelta,
  520. prclSrc,
  521. prclClip))
  522. {
  523. return(TRUE);
  524. }
  525. }
  526. else if (pco->iDComplexity == DC_RECT)
  527. {
  528. prclClip = &pco->rclBounds;
  529. goto StretchSingleClipRect;
  530. }
  531. else
  532. {
  533. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  534. do {
  535. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  536. c = cIntersect(prclDst, ce.arcl, ce.c);
  537. if (c != 0)
  538. {
  539. for (i = 0; i < c; i++)
  540. {
  541. if (!bBankedStretch(ppdev,
  542. NULL,
  543. ppdev->lDelta,
  544. prclDst,
  545. psoSrc->pvScan0,
  546. psoSrc->lDelta,
  547. prclSrc,
  548. &ce.arcl[i]))
  549. {
  550. goto Punt_It;
  551. }
  552. }
  553. }
  554. } while (bMore);
  555. return(TRUE);
  556. }
  557. }
  558. }
  559. }
  560. }
  561. Punt_It:
  562. // GDI is nice enough to handle the cases where 'psoDst' and/or 'psoSrc'
  563. // are device-managed surfaces, but it ain't gonna be fast...
  564. return(EngStretchBlt(psoDst, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg,
  565. prclDst, prclSrc, pptlMsk, iMode));
  566. }