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.

625 lines
22 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: bltio.c
  3. *
  4. * Contains the low-level in/out blt functions. This module mirrors
  5. * 'bltmm.c'.
  6. *
  7. * Hopefully, if you're basing your display driver on this code, to
  8. * support all of DrvBitBlt and DrvCopyBits, you'll only have to implement
  9. * the following routines. You shouldn't have to modify much in
  10. * 'bitblt.c'. I've tried to make these routines as few, modular, simple,
  11. * and efficient as I could, while still accelerating as many calls as
  12. * possible that would be cost-effective in terms of performance wins
  13. * versus size and effort.
  14. *
  15. * Note: In the following, 'relative' coordinates refers to coordinates
  16. * that haven't yet had the offscreen bitmap (DFB) offset applied.
  17. * 'Absolute' coordinates have had the offset applied. For example,
  18. * we may be told to blt to (1, 1) of the bitmap, but the bitmap may
  19. * be sitting in offscreen memory starting at coordinate (0, 768) --
  20. * (1, 1) would be the 'relative' start coordinate, and (1, 769)
  21. * would be the 'absolute' start coordinate'.
  22. *
  23. * Copyright (c) 1992-1995 Microsoft Corporation
  24. *
  25. \**************************************************************************/
  26. #include "precomp.h"
  27. /******************************Public*Routine******************************\
  28. * VOID vIoFillSolid
  29. *
  30. * Fills a list of rectangles with a solid colour.
  31. *
  32. \**************************************************************************/
  33. VOID vIoFillSolid( // Type FNFILL
  34. PDEV* ppdev,
  35. LONG c, // Can't be zero
  36. RECTL* prcl, // List of rectangles to be filled, in relative
  37. // coordinates
  38. ULONG rop4, // Mix
  39. RBRUSH_COLOR rbc, // Drawing colour is rbc.iSolidColor
  40. POINTL* pptlBrush) // Not used
  41. {
  42. BYTE* pjIoBase;
  43. ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
  44. pjIoBase = ppdev->pjIoBase;
  45. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  46. IO_PREG_COLOR_8(ppdev, pjIoBase, rbc.iSolidColor);
  47. IO_CTRL_REG_1(ppdev, pjIoBase, PACKED_PIXEL_VIEW |
  48. BITS_PER_PIX_8 |
  49. ENAB_TRITON_MODE);
  50. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  51. XY_DEST_ADDR);
  52. if (rop4 == 0xf0f0)
  53. {
  54. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  55. PIXELMASK_ONLY |
  56. PLANARMASK_NONE_0XFF |
  57. SRC_IS_PATTERN_REGS);
  58. }
  59. else
  60. {
  61. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  62. PIXELMASK_ONLY |
  63. PLANARMASK_NONE_0XFF |
  64. SRC_IS_PATTERN_REGS);
  65. IO_ROP_A(ppdev, pjIoBase, rop4 >> 2);
  66. }
  67. IO_BITMAP_HEIGHT(ppdev, pjIoBase, prcl->bottom - prcl->top);
  68. IO_BITMAP_WIDTH(ppdev, pjIoBase, prcl->right - prcl->left);
  69. IO_DEST_XY(ppdev, pjIoBase, prcl->left, prcl->top);
  70. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  71. while (prcl++, --c)
  72. {
  73. IO_WAIT_BUFFER_NOT_BUSY(ppdev, pjIoBase);
  74. IO_BITMAP_HEIGHT(ppdev, pjIoBase, prcl->bottom - prcl->top);
  75. IO_BITMAP_WIDTH(ppdev, pjIoBase, prcl->right - prcl->left);
  76. IO_DEST_XY(ppdev, pjIoBase, prcl->left, prcl->top);
  77. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  78. }
  79. }
  80. /******************************Public*Routine******************************\
  81. * VOID vIoFillPat2Color
  82. *
  83. * This routine uses the QVision pattern hardware to draw a patterned list of
  84. * rectangles.
  85. *
  86. \**************************************************************************/
  87. VOID vIoFillPat2Color( // Type FNFILL
  88. PDEV* ppdev,
  89. LONG c, // Can't be zero
  90. RECTL* prcl, // List of rectangles to be filled, in relative
  91. // coordinates
  92. ULONG rop4, // Mix
  93. RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
  94. POINTL* pptlBrush) // Pattern alignment
  95. {
  96. BYTE* pjIoBase;
  97. LONG xAlign;
  98. LONG yAlign;
  99. ASSERTDD(((rop4 >> 8) == (rop4 & 0xff)) || ((rop4 & 0xff00) == 0xaa00),
  100. "Illegal mix");
  101. pjIoBase = ppdev->pjIoBase;
  102. xAlign = pptlBrush->x;
  103. yAlign = pptlBrush->y;
  104. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  105. IO_FG_COLOR(ppdev, pjIoBase, rbc.prb->ulForeColor);
  106. IO_BG_COLOR(ppdev, pjIoBase, rbc.prb->ulBackColor);
  107. IO_PREG_PATTERN(ppdev, pjIoBase, rbc.prb->aulPattern);
  108. IO_CTRL_REG_1(ppdev, pjIoBase, EXPAND_TO_FG |
  109. BITS_PER_PIX_8 |
  110. ENAB_TRITON_MODE);
  111. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  112. XY_DEST_ADDR);
  113. if (rop4 == 0xf0f0)
  114. {
  115. // Opaque brush with PATCOPY rop:
  116. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  117. PIXELMASK_ONLY |
  118. PLANARMASK_NONE_0XFF |
  119. SRC_IS_PATTERN_REGS);
  120. }
  121. else if (((rop4 >> 8) & 0xff) == (rop4 & 0xff))
  122. {
  123. // Opaque brush with rop other than PATCOPY:
  124. IO_ROP_A(ppdev, pjIoBase, rop4 >> 2);
  125. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  126. PIXELMASK_ONLY |
  127. PLANARMASK_NONE_0XFF |
  128. SRC_IS_PATTERN_REGS);
  129. }
  130. else if ((rop4 & 0xff) == 0xcc)
  131. {
  132. // Transparent brush with PATCOPY rop:
  133. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  134. PIXELMASK_AND_SRC_DATA |
  135. PLANARMASK_NONE_0XFF |
  136. SRC_IS_PATTERN_REGS);
  137. }
  138. else
  139. {
  140. // Transparent brush with rop other than PATCOPY:
  141. IO_ROP_A(ppdev, pjIoBase, rop4 >> 2);
  142. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  143. PIXELMASK_AND_SRC_DATA |
  144. PLANARMASK_NONE_0XFF |
  145. SRC_IS_PATTERN_REGS);
  146. }
  147. IO_BITMAP_HEIGHT(ppdev, pjIoBase, prcl->bottom - prcl->top);
  148. IO_BITMAP_WIDTH(ppdev, pjIoBase, prcl->right - prcl->left);
  149. IO_DEST_XY(ppdev, pjIoBase, prcl->left, prcl->top);
  150. IO_SRC_ALIGN(ppdev, pjIoBase, ((prcl->left - xAlign) & 7) |
  151. ((prcl->top - yAlign) << 3));
  152. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  153. while (prcl++, --c)
  154. {
  155. IO_WAIT_BUFFER_NOT_BUSY(ppdev, pjIoBase);
  156. IO_BITMAP_HEIGHT(ppdev, pjIoBase, prcl->bottom - prcl->top);
  157. IO_BITMAP_WIDTH(ppdev, pjIoBase, prcl->right - prcl->left);
  158. IO_DEST_XY(ppdev, pjIoBase, prcl->left, prcl->top);
  159. IO_SRC_ALIGN(ppdev, pjIoBase, ((prcl->left - xAlign) & 7) |
  160. ((prcl->top - yAlign) << 3));
  161. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  162. }
  163. }
  164. /******************************Public*Routine******************************\
  165. * VOID vIoFillPat
  166. *
  167. * This routine uses the QVision pattern hardware to draw a patterned list of
  168. * rectangles.
  169. *
  170. \**************************************************************************/
  171. VOID vIoFillPat( // Type FNFILL
  172. PDEV* ppdev,
  173. LONG c, // Can't be zero
  174. RECTL* prcl, // List of rectangles to be filled, in relative
  175. // coordinates
  176. ULONG rop4, // Mix
  177. RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
  178. POINTL* pptlBrush) // Pattern alignment
  179. {
  180. BYTE* pjIoBase;
  181. LONG xAlign;
  182. LONG yAlign;
  183. LONG lLinearDelta;
  184. BYTE* pjPattern;
  185. LONG xLeft;
  186. LONG yTop;
  187. LONG yBottom;
  188. LONG lLinearDest;
  189. LONG cy;
  190. LONG iPattern;
  191. LONG cyHeightOfEachBlt;
  192. LONG cBltsBeforeHeightChange;
  193. LONG cBlts;
  194. if (!(rbc.prb->fl & RBRUSH_2COLOR))
  195. {
  196. ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
  197. pjIoBase = ppdev->pjIoBase;
  198. xAlign = pptlBrush->x;
  199. yAlign = pptlBrush->y;
  200. lLinearDelta = ppdev->lDelta << 3;
  201. pjPattern = (BYTE*) rbc.prb->aulPattern;
  202. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  203. IO_DEST_PITCH(ppdev, pjIoBase, (ppdev->lDelta << rbc.prb->cyLog2) >> 2);
  204. IO_CTRL_REG_1(ppdev, pjIoBase, PACKED_PIXEL_VIEW |
  205. BITS_PER_PIX_8 |
  206. ENAB_TRITON_MODE);
  207. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  208. LIN_DEST_ADDR);
  209. if (rop4 == 0xf0f0)
  210. {
  211. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  212. PIXELMASK_ONLY |
  213. PLANARMASK_NONE_0XFF |
  214. SRC_IS_PATTERN_REGS);
  215. }
  216. else
  217. {
  218. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  219. PIXELMASK_ONLY |
  220. PLANARMASK_NONE_0XFF |
  221. SRC_IS_PATTERN_REGS);
  222. IO_ROP_A(ppdev, pjIoBase, rop4 >> 2);
  223. }
  224. while (TRUE)
  225. {
  226. xLeft = prcl->left;
  227. yTop = prcl->top;
  228. lLinearDest = ((yTop + ppdev->yOffset) * lLinearDelta)
  229. + ((xLeft + ppdev->xOffset) << 3);
  230. // Note that any registers we set now before the
  231. // WAIT_FOR_IDLE must be buffered, as this loop may be
  232. // executed multiple times when doing more than one
  233. // rectangle:
  234. IO_BITMAP_WIDTH(ppdev, pjIoBase, prcl->right - xLeft);
  235. IO_DEST_X(ppdev, pjIoBase, xLeft);
  236. IO_SRC_ALIGN(ppdev, pjIoBase, xLeft - xAlign);
  237. yBottom = prcl->bottom;
  238. cy = yBottom - yTop;
  239. iPattern = 8 * (yTop - yAlign);
  240. cyHeightOfEachBlt = (cy >> rbc.prb->cyLog2) + 1;
  241. cBlts = min(cy, rbc.prb->cy);
  242. cBltsBeforeHeightChange = (cy & (rbc.prb->cy - 1)) + 1;
  243. if (cBltsBeforeHeightChange != 1)
  244. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cyHeightOfEachBlt);
  245. do {
  246. // Need to wait for idle because we're about to modify the
  247. // pattern registers, which aren't buffered:
  248. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  249. IO_PREG_PATTERN(ppdev, pjIoBase, pjPattern + (iPattern & 63));
  250. iPattern += 8;
  251. IO_DEST_LIN(ppdev, pjIoBase, lLinearDest);
  252. lLinearDest += lLinearDelta;
  253. cBltsBeforeHeightChange--;
  254. if (cBltsBeforeHeightChange == 0)
  255. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cyHeightOfEachBlt - 1);
  256. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  257. } while (--cBlts != 0);
  258. if (--c == 0)
  259. break;
  260. prcl++;
  261. }
  262. }
  263. else
  264. {
  265. vIoFillPat2Color(ppdev, c, prcl, rop4, rbc, pptlBrush);
  266. }
  267. }
  268. /******************************Public*Routine******************************\
  269. * VOID vIoXfer1bpp
  270. *
  271. * This routine colours expands a monochrome bitmap, possibly with different
  272. * Rop2's for the foreground and background. It will be called in the
  273. * following cases:
  274. *
  275. * 1) To colour-expand the monochrome text buffer for the vFastText routine.
  276. * 2) To blt a 1bpp source with a simple Rop2 between the source and
  277. * destination.
  278. * 3) To blt a true Rop3 when the source is a 1bpp bitmap that expands to
  279. * white and black, and the pattern is a solid colour.
  280. * 4) To handle a true Rop4 that works out to be Rop2's between the pattern
  281. * and destination.
  282. *
  283. * Needless to say, making this routine fast can leverage a lot of
  284. * performance.
  285. *
  286. \**************************************************************************/
  287. VOID vIoXfer1bpp( // Type FNXFER
  288. PDEV* ppdev,
  289. LONG c, // Count of rectangles, can't be zero
  290. RECTL* prcl, // List of destination rectangles, in relative
  291. // coordinates
  292. ULONG rop4, // Mix
  293. SURFOBJ* psoSrc, // Source surface
  294. POINTL* pptlSrc, // Original unclipped source point
  295. RECTL* prclDst, // Original unclipped destination rectangle
  296. XLATEOBJ* pxlo) // Translate that provides colour-expansion information
  297. {
  298. BYTE* pjIoBase;
  299. LONG dxSrc;
  300. LONG dySrc; // Add delta to destination to get source
  301. LONG lSrcDelta;
  302. BYTE* pjSrcScan0;
  303. BYTE* pjDstStart;
  304. LONG yTop;
  305. LONG xLeft;
  306. LONG xRight;
  307. LONG cx;
  308. LONG cy; // Dimensions of blt rectangle
  309. LONG xBias;
  310. LONG cjSrc;
  311. LONG cdSrc;
  312. LONG lSrcSkip;
  313. BYTE* pjSrc;
  314. BYTE* pjDst;
  315. LONG i;
  316. LONG j;
  317. ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
  318. pjIoBase = ppdev->pjIoBase;
  319. dxSrc = pptlSrc->x - prclDst->left;
  320. dySrc = pptlSrc->y - prclDst->top;
  321. lSrcDelta = psoSrc->lDelta;
  322. pjSrcScan0 = psoSrc->pvScan0;
  323. pjDstStart = ppdev->pjScreen;
  324. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  325. IO_CTRL_REG_1(ppdev, pjIoBase, EXPAND_TO_FG |
  326. BITS_PER_PIX_8 |
  327. ENAB_TRITON_MODE);
  328. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  329. XY_DEST_ADDR);
  330. IO_FG_COLOR(ppdev, pjIoBase, pxlo->pulXlate[1]);
  331. IO_BG_COLOR(ppdev, pjIoBase, pxlo->pulXlate[0]);
  332. if (rop4 == 0xcccc)
  333. {
  334. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  335. PIXELMASK_ONLY |
  336. PLANARMASK_NONE_0XFF |
  337. SRC_IS_CPU_DATA);
  338. }
  339. else
  340. {
  341. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  342. PIXELMASK_ONLY |
  343. PLANARMASK_NONE_0XFF |
  344. SRC_IS_CPU_DATA);
  345. IO_ROP_A(ppdev, pjIoBase, rop4);
  346. }
  347. while (TRUE)
  348. {
  349. yTop = prcl->top;
  350. xLeft = prcl->left;
  351. xRight = prcl->right;
  352. cy = prcl->bottom - yTop;
  353. cx = xRight - xLeft;
  354. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  355. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  356. IO_DEST_XY(ppdev, pjIoBase, xLeft, yTop);
  357. xBias = (xLeft + dxSrc) & 7;
  358. IO_SRC_ALIGN(ppdev, pjIoBase, xBias);
  359. xLeft -= xBias;
  360. cjSrc = (xRight - xLeft + 7) >> 3;
  361. cdSrc = cjSrc >> 2;
  362. lSrcSkip = lSrcDelta - (cdSrc << 2);
  363. pjSrc = pjSrcScan0 + (yTop + dySrc) * lSrcDelta
  364. + ((xLeft + dxSrc) >> 3);
  365. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  366. switch(cjSrc & 3)
  367. {
  368. case 0:
  369. for (i = cy; i != 0; i--)
  370. {
  371. MEMORY_BARRIER();
  372. pjDst = pjDstStart;
  373. for (j = cdSrc; j != 0; j--)
  374. {
  375. WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
  376. pjDst += sizeof(ULONG);
  377. pjSrc += sizeof(ULONG);
  378. }
  379. pjSrc += lSrcSkip;
  380. }
  381. break;
  382. case 1:
  383. for (i = cy; i != 0; i--)
  384. {
  385. MEMORY_BARRIER();
  386. pjDst = pjDstStart;
  387. for (j = cdSrc; j != 0; j--)
  388. {
  389. WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
  390. pjDst += sizeof(ULONG);
  391. pjSrc += sizeof(ULONG);
  392. }
  393. WRITE_REGISTER_UCHAR(pjDst, *pjSrc);
  394. pjSrc += lSrcSkip;
  395. }
  396. break;
  397. case 2:
  398. for (i = cy; i != 0; i--)
  399. {
  400. MEMORY_BARRIER();
  401. pjDst = pjDstStart;
  402. for (j = cdSrc; j != 0; j--)
  403. {
  404. WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
  405. pjDst += sizeof(ULONG);
  406. pjSrc += sizeof(ULONG);
  407. }
  408. WRITE_REGISTER_USHORT(pjDst, *((USHORT UNALIGNED *) pjSrc));
  409. pjSrc += lSrcSkip;
  410. }
  411. break;
  412. case 3:
  413. for (i = cy; i != 0; i--)
  414. {
  415. MEMORY_BARRIER();
  416. pjDst = pjDstStart;
  417. for (j = cdSrc; j != 0; j--)
  418. {
  419. WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
  420. pjDst += sizeof(ULONG);
  421. pjSrc += sizeof(ULONG);
  422. }
  423. WRITE_REGISTER_USHORT(pjDst, *((USHORT UNALIGNED *) pjSrc));
  424. WRITE_REGISTER_UCHAR((pjDst + 2), *(pjSrc + 2));
  425. pjSrc += lSrcSkip;
  426. }
  427. break;
  428. }
  429. IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase);
  430. if (--c == 0)
  431. break;
  432. prcl++;
  433. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  434. }
  435. // Give the Triton a kick in the pants to work around a goofy
  436. // hardware bug:
  437. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  438. IO_BLT_CONFIG(ppdev, pjIoBase, RESET_BLT);
  439. IO_BLT_CONFIG(ppdev, pjIoBase, BLT_ENABLE);
  440. }
  441. /******************************Public*Routine******************************\
  442. * VOID vIoCopyBlt
  443. *
  444. * Does a screen-to-screen blt of a list of rectangles.
  445. *
  446. \**************************************************************************/
  447. VOID vIoCopyBlt( // Type FNCOPY
  448. PDEV* ppdev,
  449. LONG c, // Can't be zero
  450. RECTL* prcl, // Array of relative coordinates destination rectangles
  451. ULONG rop4, // Hardware mix
  452. POINTL* pptlSrc, // Original unclipped source point
  453. RECTL* prclDst) // Original unclipped destination rectangle
  454. {
  455. BYTE* pjIoBase;
  456. LONG dxSrc;
  457. LONG dySrc; // Add delta to destination to get source
  458. LONG cx;
  459. LONG cy; // Dimensions of blt rectangle
  460. LONG xDst;
  461. LONG yDst; // Start point of destination
  462. ASSERTDD((rop4 >> 8) == (rop4 & 0xff), "Illegal mix");
  463. pjIoBase = ppdev->pjIoBase;
  464. dxSrc = pptlSrc->x - prclDst->left;
  465. dySrc = pptlSrc->y - prclDst->top;
  466. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  467. IO_CTRL_REG_1(ppdev, pjIoBase, PACKED_PIXEL_VIEW | // !!! Need this each time?
  468. BITS_PER_PIX_8 |
  469. ENAB_TRITON_MODE);
  470. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  471. XY_DEST_ADDR);
  472. if (rop4 == 0xcccc)
  473. {
  474. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  475. PIXELMASK_ONLY |
  476. PLANARMASK_NONE_0XFF |
  477. SRC_IS_SCRN_LATCHES);
  478. }
  479. else
  480. {
  481. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_ALL |
  482. PIXELMASK_ONLY |
  483. PLANARMASK_NONE_0XFF |
  484. SRC_IS_SCRN_LATCHES);
  485. IO_ROP_A(ppdev, pjIoBase, rop4);
  486. }
  487. if ((prclDst->top < pptlSrc->y) ||
  488. (prclDst->top == pptlSrc->y) && (prclDst->left <= pptlSrc->x))
  489. {
  490. // Forward blt:
  491. cx = prcl->right - prcl->left;
  492. cy = prcl->bottom - prcl->top;
  493. xDst = prcl->left;
  494. yDst = prcl->top;
  495. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  496. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  497. IO_DEST_XY(ppdev, pjIoBase, xDst, yDst);
  498. IO_SRC_XY(ppdev, pjIoBase, xDst + dxSrc, yDst + dySrc);
  499. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  500. while (prcl++, --c)
  501. {
  502. cx = prcl->right - prcl->left;
  503. cy = prcl->bottom - prcl->top;
  504. xDst = prcl->left;
  505. yDst = prcl->top;
  506. IO_WAIT_BUFFER_NOT_BUSY(ppdev, pjIoBase);
  507. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  508. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  509. IO_DEST_XY(ppdev, pjIoBase, xDst, yDst);
  510. IO_SRC_XY(ppdev, pjIoBase, xDst + dxSrc, yDst + dySrc);
  511. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  512. }
  513. }
  514. else
  515. {
  516. // Backward blt:
  517. cx = prcl->right - prcl->left;
  518. cy = prcl->bottom - prcl->top;
  519. xDst = prcl->left + cx - 1;
  520. yDst = prcl->top + cy - 1;
  521. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  522. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  523. IO_DEST_XY(ppdev, pjIoBase, xDst, yDst);
  524. IO_SRC_XY(ppdev, pjIoBase, xDst + dxSrc, yDst + dySrc);
  525. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT | BACKWARD);
  526. while (prcl++, --c)
  527. {
  528. cx = prcl->right - prcl->left;
  529. cy = prcl->bottom - prcl->top;
  530. xDst = prcl->left + cx - 1;
  531. yDst = prcl->top + cy - 1;
  532. IO_WAIT_BUFFER_NOT_BUSY(ppdev, pjIoBase);
  533. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  534. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  535. IO_DEST_XY(ppdev, pjIoBase, xDst, yDst);
  536. IO_SRC_XY(ppdev, pjIoBase, xDst + dxSrc, yDst + dySrc);
  537. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT | BACKWARD);
  538. }
  539. }
  540. }