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.

860 lines
26 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: blt8.c
  3. *
  4. * This module contains the low-level blt functions that are specific to
  5. * 8bpp.
  6. *
  7. * Copyright (c) 1992-1996 Microsoft Corporation
  8. * Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
  9. \**************************************************************************/
  10. #include "precomp.h"
  11. /******************************Public*Routine******************************\
  12. * VOID vMgaPatRealize8bpp
  13. *
  14. \**************************************************************************/
  15. VOID vMgaPatRealize8bpp(
  16. PDEV* ppdev,
  17. RBRUSH* prb)
  18. {
  19. BYTE* pjBase;
  20. BRUSHENTRY* pbe;
  21. LONG iBrushCache;
  22. LONG i;
  23. ULONG* pulSrc;
  24. pjBase = ppdev->pjBase;
  25. // We have to allocate a new off-screen cache brush entry for
  26. // the brush:
  27. iBrushCache = ppdev->iBrushCache;
  28. pbe = &ppdev->pbe[iBrushCache];
  29. iBrushCache++;
  30. if (iBrushCache >= ppdev->cBrushCache)
  31. iBrushCache = 0;
  32. ppdev->iBrushCache = iBrushCache;
  33. // Update our links:
  34. pbe->prbVerify = prb;
  35. prb->apbe[IBOARD(ppdev)] = pbe;
  36. CHECK_FIFO_SPACE(pjBase, 11);
  37. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_ILOAD + atype_RPL + blockm_OFF +
  38. bop_SRCCOPY + bltmod_BFCOL + pattern_OFF +
  39. transc_BG_OPAQUE));
  40. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  41. {
  42. CP_WRITE(pjBase, DWG_SGN, 0);
  43. }
  44. // The SRC0 - SRC3 registers will be trashed by the blt:
  45. ppdev->HopeFlags = SIGN_CACHE;
  46. // Since our brushes are always interleaved, we want to send down
  47. // 2 pels, skip 2 pels, send down 2 pels, etc. So we contrive to
  48. // adjust the blt width and pitch to do that automatically for us:
  49. CP_WRITE(pjBase, DWG_AR3, 0); // Source start address, not
  50. // included in ARX_CACHE
  51. CP_WRITE(pjBase, DWG_SHIFT, 0);
  52. CP_WRITE(pjBase, DWG_LEN, 8); // Transfering 8 scans
  53. CP_WRITE(pjBase, DWG_AR0, 15); // Source width is 16
  54. CP_WRITE(pjBase, DWG_AR5, 32); // Source pitch is 32
  55. CP_WRITE(pjBase, DWG_FXLEFT, pbe->ulLeft);
  56. CP_WRITE(pjBase, DWG_FXRIGHT, pbe->ulLeft + 15);
  57. CP_WRITE(pjBase, DWG_YDST, pbe->ulYDst);
  58. CP_START(pjBase, DWG_PITCH, 32);
  59. CHECK_FIFO_SPACE(pjBase, 32);
  60. for (pulSrc = prb->aulPattern, i = 8; i != 0; i--, pulSrc += 2)
  61. {
  62. CP_WRITE_SRC(pjBase, *(pulSrc));
  63. CP_WRITE_SRC(pjBase, *(pulSrc + 1));
  64. // Repeat the brush's scan, because the off-screen pattern has to
  65. // be 16 x 8:
  66. CP_WRITE_SRC(pjBase, *(pulSrc));
  67. CP_WRITE_SRC(pjBase, *(pulSrc + 1));
  68. }
  69. // Don't forget to restore the pitch:
  70. CHECK_FIFO_SPACE(pjBase, 1);
  71. CP_WRITE(pjBase, DWG_PITCH, ppdev->cxMemory);
  72. }
  73. /******************************Public*Routine******************************\
  74. * VOID vMgaFillPat8bppWorkAround
  75. *
  76. * Works around an MGA hardware bug with colour patterns and hardware ROPs.
  77. *
  78. \**************************************************************************/
  79. VOID vMgaFillPat8bppWorkAround( // Type FNFILL
  80. PDEV* ppdev,
  81. LONG c, // Can't be zero
  82. RECTL* prcl, // List of rectangles to be filled, in relative
  83. // coordinates
  84. ULONG rop4, // Rop4
  85. RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
  86. POINTL* pptlBrush) // Pattern alignment
  87. {
  88. BYTE* pjBase;
  89. BRUSHENTRY* pbe;
  90. LONG xOffset;
  91. LONG yOffset;
  92. ULONG ulHwMix;
  93. LONG yTop;
  94. LONG xLeft;
  95. LONG xBrush;
  96. LONG yBrush;
  97. ULONG ulLinear;
  98. ULONG ulLinear0;
  99. ULONG ulLinear3;
  100. LONG cx;
  101. LONG cy;
  102. LONG cxSlice;
  103. LONG cLoops;
  104. ASSERTDD(!(rbc.prb->fl & RBRUSH_2COLOR), "Can't do 2 colour brushes here");
  105. ASSERTDD(rop4 != 0xf0f0, "PATCOPY should already have been handled");
  106. ASSERTDD(rbc.prb->apbe[IBOARD(ppdev)]->prbVerify == rbc.prb,
  107. "Brush realization should have been handled by vFillPat8bpp");
  108. pbe = rbc.prb->apbe[IBOARD(ppdev)];
  109. pjBase = ppdev->pjBase;
  110. xOffset = ppdev->xOffset;
  111. yOffset = ppdev->yOffset;
  112. CHECK_FIFO_SPACE(pjBase, 10);
  113. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  114. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RSTR + blockm_OFF +
  115. trans_0 + bltmod_BFCOL + pattern_ON +
  116. transc_BG_OPAQUE + (ulHwMix << 16)));
  117. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  118. {
  119. CP_WRITE(pjBase, DWG_SGN, 0);
  120. }
  121. ppdev->HopeFlags = SIGN_CACHE;
  122. CP_WRITE(pjBase, DWG_SHIFT, 0);
  123. CP_WRITE(pjBase, DWG_AR5, 32);
  124. while (TRUE)
  125. {
  126. yTop = prcl->top;
  127. xLeft = prcl->left;
  128. xBrush = (xLeft - pptlBrush->x) & 7;
  129. yBrush = (yTop - pptlBrush->y) & 7;
  130. ulLinear = pbe->ulLinear + (yBrush << 5);
  131. CP_WRITE(pjBase, DWG_AR3, ulLinear + xBrush);
  132. CP_WRITE(pjBase, DWG_AR0, ulLinear + 15);
  133. CP_WRITE(pjBase, DWG_LEN, prcl->bottom - yTop);
  134. CP_WRITE(pjBase, DWG_YDST, yOffset + yTop);
  135. CP_WRITE(pjBase, DWG_FXLEFT, xOffset + xLeft);
  136. // We do the fix by setting FXRIGHT to mark the end of our first
  137. // slice, start the engine, then draw full-width (32 pel wide)
  138. // slices, if any, and then the last (partial) slice, if required:
  139. cx = prcl->right - xLeft;
  140. cxSlice = 32 - ((xLeft + xOffset) & 0xf);
  141. if (cx <= cxSlice)
  142. {
  143. // We can still use the fast way:
  144. CP_START(pjBase, DWG_FXRIGHT, xOffset + prcl->right - 1);
  145. }
  146. else
  147. {
  148. // Do the first slice:
  149. xLeft += cxSlice;
  150. cx -= cxSlice;
  151. CP_START(pjBase, DWG_FXRIGHT, xOffset + xLeft - 1);
  152. // Recompute the new brush alignment:
  153. xBrush = (xLeft - pptlBrush->x) & 7;
  154. ulLinear3 = ulLinear + xBrush;
  155. ulLinear0 = ulLinear + 15;
  156. // Convert to absolute coordinates from here on:
  157. cy = prcl->bottom - yTop;
  158. xLeft += xOffset;
  159. yTop += yOffset;
  160. // Do any full-width slices:
  161. for (cLoops = (cx >> 5); cLoops != 0; cLoops--)
  162. {
  163. CHECK_FIFO_SPACE(pjBase, 6);
  164. CP_WRITE(pjBase, DWG_AR3, ulLinear3);
  165. CP_WRITE(pjBase, DWG_AR0, ulLinear0);
  166. CP_WRITE(pjBase, DWG_LEN, cy);
  167. CP_WRITE(pjBase, DWG_YDST, yTop);
  168. CP_WRITE(pjBase, DWG_FXLEFT, xLeft);
  169. xLeft += 32;
  170. CP_START(pjBase, DWG_FXRIGHT, xLeft - 1);
  171. }
  172. // Do any partial last slice:
  173. cx &= 31;
  174. if (cx > 0)
  175. {
  176. CHECK_FIFO_SPACE(pjBase, 6);
  177. // We've got to reload these registers each time:
  178. CP_WRITE(pjBase, DWG_AR3, ulLinear3);
  179. CP_WRITE(pjBase, DWG_AR0, ulLinear0);
  180. CP_WRITE(pjBase, DWG_LEN, cy);
  181. CP_WRITE(pjBase, DWG_YDST, yTop);
  182. CP_WRITE(pjBase, DWG_FXLEFT, xLeft);
  183. CP_START(pjBase, DWG_FXRIGHT, xLeft + cx - 1);
  184. }
  185. }
  186. if (--c == 0)
  187. break;
  188. prcl++;
  189. CHECK_FIFO_SPACE(pjBase, 6);
  190. }
  191. }
  192. /******************************Public*Routine******************************\
  193. * VOID vFillPat8bpp
  194. *
  195. \**************************************************************************/
  196. VOID vMgaFillPat8bpp( // Type FNFILL
  197. PDEV* ppdev,
  198. LONG c, // Can't be zero
  199. RECTL* prcl, // List of rectangles to be filled, in relative
  200. // coordinates
  201. ULONG rop4, // Rop4
  202. RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
  203. POINTL* pptlBrush) // Pattern alignment
  204. {
  205. BYTE* pjBase;
  206. BRUSHENTRY* pbe;
  207. LONG xOffset;
  208. LONG yOffset;
  209. ULONG ulHwMix;
  210. LONG yTop;
  211. LONG xLeft;
  212. LONG xBrush;
  213. LONG yBrush;
  214. ULONG ulLinear;
  215. ASSERTDD(!(rbc.prb->fl & RBRUSH_2COLOR), "Can't do 2 colour brushes here");
  216. ASSERTDD((rbc.prb != NULL) && (rbc.prb->apbe[IBOARD(ppdev)] != NULL),
  217. "apbe[iBoard] should be initialized to &beUnrealizedBrush");
  218. // We have to ensure that no other brush took our spot in off-screen
  219. // memory, or we might have to realize the brush for the first time:
  220. pbe = rbc.prb->apbe[IBOARD(ppdev)];
  221. if (pbe->prbVerify != rbc.prb)
  222. {
  223. vMgaPatRealize8bpp(ppdev, rbc.prb);
  224. pbe = rbc.prb->apbe[IBOARD(ppdev)];
  225. }
  226. pjBase = ppdev->pjBase;
  227. xOffset = ppdev->xOffset;
  228. yOffset = ppdev->yOffset;
  229. CHECK_FIFO_SPACE(pjBase, 10);
  230. if (rop4 == 0xf0f0) // PATCOPY
  231. {
  232. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RPL + blockm_OFF +
  233. trans_0 + bltmod_BFCOL + pattern_ON +
  234. transc_BG_OPAQUE + bop_SRCCOPY));
  235. }
  236. else
  237. {
  238. {
  239. // On some MGA chips, we have to work around a hardware bug
  240. // with arbitrary ROPs:
  241. vMgaFillPat8bppWorkAround(ppdev, c, prcl, rop4, rbc, pptlBrush);
  242. return;
  243. }
  244. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  245. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RSTR + blockm_OFF +
  246. trans_0 + bltmod_BFCOL + pattern_ON +
  247. transc_BG_OPAQUE + (ulHwMix << 16)));
  248. }
  249. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  250. {
  251. CP_WRITE(pjBase, DWG_SGN, 0);
  252. }
  253. ppdev->HopeFlags = SIGN_CACHE;
  254. CP_WRITE(pjBase, DWG_SHIFT, 0);
  255. CP_WRITE(pjBase, DWG_AR5, 32);
  256. while (TRUE)
  257. {
  258. yTop = prcl->top;
  259. xLeft = prcl->left;
  260. xBrush = (xLeft - pptlBrush->x) & 7;
  261. yBrush = (yTop - pptlBrush->y) & 7;
  262. ulLinear = pbe->ulLinear + (yBrush << 5);
  263. CP_WRITE(pjBase, DWG_AR3, ulLinear + xBrush);
  264. CP_WRITE(pjBase, DWG_AR0, ulLinear + 15);
  265. CP_WRITE(pjBase, DWG_LEN, prcl->bottom - yTop);
  266. CP_WRITE(pjBase, DWG_YDST, yOffset + yTop);
  267. CP_WRITE(pjBase, DWG_FXLEFT, xOffset + xLeft);
  268. CP_START(pjBase, DWG_FXRIGHT, xOffset + prcl->right - 1);
  269. if (--c == 0)
  270. break;
  271. prcl++;
  272. CHECK_FIFO_SPACE(pjBase, 6);
  273. }
  274. }
  275. /******************************Public*Routine******************************\
  276. * VOID vMgaGet8bppSliceFromScreen
  277. *
  278. * Get a limited number of pels from the screen and make sure that the
  279. * transfer went OK. This assumes that the IDUMP is almost fully set up,
  280. * and that a number of dwords must be jumped over at the end of each
  281. * destination scanline.
  282. *
  283. \**************************************************************************/
  284. VOID vMgaGet8bppSliceFromScreen(
  285. PDEV* ppdev, // pdev
  286. ULONG ulSSA, // Source start address for current slice
  287. ULONG ulSEA, // Source end address for current slice
  288. ULONG ulLen, // Nb of scanlines in current slice
  289. LONG NbDWordsPerScan,// Nb of dwords to be read in each scanline
  290. LONG NbFirstBytes, // Nb bytes to be used from 1st dword
  291. LONG NbLastBytes, // Nb bytes to be used from 2nd (last) dword
  292. LONG lPreDWordBytes, // Nb bytes before any dword on a scan
  293. LONG lDWords, // Nb dwords to be moved on a scan
  294. LONG lPostDWordBytes,// Nb bytes after all dwords on a scan
  295. LONG lDestDelta, // Increment to get from one dest scan to the next
  296. BYTE bPreShift, // Shift to align first byte to be stored
  297. ULONG** ppulDest) // Ptr to where to store the first dword we read
  298. {
  299. BYTE* pjBase;
  300. ULONG temp, HstStatus, AbortCnt;
  301. ULONG* pulDest;
  302. ULONG* locpulDest;
  303. ULONG* pDMAWindow;
  304. LONG i, TotalDWords, locTotalDWords;
  305. BYTE* pbDest;
  306. AbortCnt = 1000;
  307. pjBase = ppdev->pjBase;
  308. pDMAWindow = (ULONG*) (pjBase+ DMAWND);
  309. // We want to stop reading just before the last dword is read.
  310. TotalDWords = (NbDWordsPerScan * ulLen) - 1;
  311. do
  312. {
  313. CHECK_FIFO_SPACE(pjBase, 3);
  314. // This is where we'll start storing data.
  315. pulDest = *ppulDest;
  316. // Complete the IDUMP setup.
  317. CP_WRITE(pjBase, DWG_AR3, ulSSA);
  318. CP_WRITE(pjBase, DWG_AR0, ulSEA);
  319. // Turn the pseudoDMA on.
  320. BLT_READ_ON(ppdev, pjBase);
  321. CP_START(pjBase, DWG_LEN, ulLen);
  322. // Make sure the setup is complete.
  323. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  324. if (TotalDWords)
  325. {
  326. // There is at least one dword left to be read.
  327. // Make a copy so that we can play with it.
  328. locTotalDWords = TotalDWords;
  329. do
  330. {
  331. // Make a copy for updating to the next scan.
  332. locpulDest = pulDest;
  333. if (lPreDWordBytes)
  334. {
  335. // There are pixels to be stored as bytes.
  336. // Read 4 pixels and shift them into place.
  337. locTotalDWords--;
  338. temp = CP_READ_DMA(ppdev, pDMAWindow);
  339. temp >>= bPreShift;
  340. pbDest = (BYTE*)pulDest;
  341. for (i = 0; i < NbFirstBytes; i++)
  342. {
  343. *pbDest = (BYTE)temp;
  344. temp >>= 8;
  345. pbDest++;
  346. }
  347. pulDest = (ULONG*)pbDest;
  348. if (locTotalDWords == 0)
  349. {
  350. // This was the end of the current slice.
  351. // Exit the do-while loop.
  352. if (NbDWordsPerScan == 1)
  353. {
  354. // Since it was a narrow slice, the next read
  355. // goes on the next scan, so add in the delta:
  356. (UCHAR*) pulDest = (UCHAR*) locpulDest + lDestDelta;
  357. pbDest = (UCHAR*) pulDest;
  358. }
  359. break;
  360. }
  361. if (NbLastBytes > 0)
  362. {
  363. // We need more pixels.
  364. locTotalDWords--;
  365. temp = CP_READ_DMA(ppdev, pDMAWindow);
  366. for (i = 0; i < NbLastBytes; i++)
  367. {
  368. *pbDest = (BYTE)temp;
  369. temp >>= 8;
  370. pbDest++;
  371. }
  372. // We should be done with this scan.
  373. }
  374. }
  375. // We should be dword-aligned in the destination now.
  376. // Copy a number of full dwords from the current scanline.
  377. for (i = 0; i < lDWords; i++)
  378. {
  379. *pulDest++ = CP_READ_DMA(ppdev, pDMAWindow);
  380. }
  381. // We're left with this many dwords to be read.
  382. locTotalDWords -= lDWords;
  383. if (locTotalDWords != 0)
  384. {
  385. // This was not the last scanline, so we must read a
  386. // possibly partial dword to end this scan.
  387. if (lPostDWordBytes)
  388. {
  389. // There are pixels to be stored as bytes.
  390. locTotalDWords--;
  391. temp = CP_READ_DMA(ppdev, pDMAWindow);
  392. pbDest = (BYTE*)pulDest;
  393. for (i = 0; i < lPostDWordBytes; i++)
  394. {
  395. *pbDest = (BYTE)temp;
  396. temp >>= 8;
  397. pbDest++;
  398. }
  399. }
  400. // We should be done with this scan.
  401. // We're done with the current scan, go to the next one.
  402. (UCHAR*) pulDest = (UCHAR*) locpulDest + lDestDelta;
  403. }
  404. } while (locTotalDWords > 0);
  405. }
  406. // Check for the EngineBusy flag.
  407. for (i = 0; i < 7; i++)
  408. {
  409. HstStatus = CP_READ_STATUS(pjBase);
  410. }
  411. if (HstStatus &= (dwgengsts_MASK >> 16))
  412. {
  413. // The drawing engine is still busy, while it should not be:
  414. // there was a problem with this slice.
  415. // Empty the DMA window.
  416. do
  417. {
  418. CP_READ_DMA(ppdev, pDMAWindow);
  419. // Check for the EngineBusy flag. If the engine is still
  420. // busy, then we'll have to read another dword.
  421. for (i = 0; i < 7; i++)
  422. {
  423. temp = CP_READ_STATUS(pjBase);
  424. }
  425. } while (temp & (dwgengsts_MASK >> 16));
  426. // The DMA window should now be empty.
  427. // We cannot check the HST_STATUS two lower bytes anymore,
  428. // so this is new.
  429. if (--AbortCnt > 0)
  430. {
  431. // Signal we'll have to do this again.
  432. HstStatus = 1;
  433. }
  434. else
  435. {
  436. // We tried hard enough, desist.
  437. HstStatus = 0;
  438. }
  439. }
  440. // The last dword to be read should be available now.
  441. temp = CP_READ_DMA(ppdev, pDMAWindow);
  442. // We must take some care so as not to write after the end of the
  443. // destination bitmap.
  444. pbDest = (BYTE*)pulDest;
  445. if (NbDWordsPerScan == 1)
  446. {
  447. // The X extent was smaller than 4.
  448. for (i = 0; i < NbFirstBytes; i++)
  449. {
  450. *pbDest = (BYTE)temp;
  451. temp >>= 8;
  452. pbDest++;
  453. }
  454. }
  455. else if (NbLastBytes > 0)
  456. {
  457. // The X extent was 5 or 6: we wrote only bytes into the dest.
  458. for (i = 0; i < NbLastBytes; i++)
  459. {
  460. *pbDest = (BYTE)temp;
  461. temp >>= 8;
  462. pbDest++;
  463. }
  464. }
  465. else if (lPostDWordBytes > 0)
  466. {
  467. // There are pixels to be stored as bytes.
  468. if (lPostDWordBytes == 4)
  469. {
  470. // We can store a dword.
  471. *pulDest = temp;
  472. }
  473. else
  474. {
  475. for (i = 0; i < lPostDWordBytes; i++)
  476. {
  477. *pbDest = (BYTE)temp;
  478. temp >>= 8;
  479. pbDest++;
  480. }
  481. }
  482. }
  483. else
  484. {
  485. // Store the last dword.
  486. *pulDest = temp;
  487. }
  488. // Turn the pseudoDMA off.
  489. BLT_READ_OFF(ppdev, pjBase);
  490. // Redo the whole thing if there was a problem with this slice.
  491. } while (HstStatus);
  492. // Update the destination pointer for the calling routine.
  493. *ppulDest += ((ulLen * lDestDelta) / sizeof(ULONG));
  494. }
  495. /******************************Public*Routine******************************\
  496. * VOID vMgaGetBits8bpp
  497. *
  498. * Reads the bits from the screen at 8bpp.
  499. *
  500. \**************************************************************************/
  501. VOID vMgaGetBits8bpp(
  502. PDEV* ppdev, // Current src pdev
  503. SURFOBJ* psoDst, // Destination surface for the color bits
  504. RECTL* prclDst, // Area to be modified within the dest surface,
  505. // in absolute coordinates
  506. POINTL* pptlSrc) // Upper left corner of source rectangle,
  507. // in absolute coordinates
  508. {
  509. BYTE* pjBase;
  510. INT i, j;
  511. BYTE* pbScan0;
  512. BYTE* pbDestRect;
  513. BYTE* pByte;
  514. BYTE* LocalpByte;
  515. LONG xSrc, ySrc, xTrg, yTrg, cxTrg, cyTrg, lDestDelta, cySlice,
  516. xTrgAl, xTrgInvAl, cxTrgAl, lPreDWordBytes, lDWords,
  517. lPostDWordBytes, NbFirstBytes, NbLastBytes, NbDWordsPerScan;
  518. ULONG temp, ulSSA, ulSEA, ulSSAIncrement,
  519. NbDWords, NbBytesPerScan;
  520. ULONG* pDW;
  521. ULONG* pulXlate;
  522. ULONG* pDMAWindow;
  523. BYTE bPreShift;
  524. pjBase = ppdev->pjBase;
  525. // Calculate the size of the target rectangle, and pick up
  526. // some convenient locals.
  527. // Starting (x,y) and extents within the destination bitmap.
  528. cxTrg = prclDst->right - prclDst->left;
  529. cyTrg = prclDst->bottom - prclDst->top;
  530. xTrg = prclDst->left;
  531. yTrg = prclDst->top;
  532. ASSERTDD(cxTrg > 0 && cyTrg > 0, "Shouldn't get empty extents");
  533. // First scanline of the destination bitmap.
  534. pbScan0 = (BYTE*) psoDst->pvScan0;
  535. // Starting (x,y) on the screen.
  536. xSrc = pptlSrc->x;
  537. ySrc = pptlSrc->y;
  538. // Scan increment within the destination bitmap.
  539. lDestDelta = psoDst->lDelta;
  540. // Calculate the location of the destination rectangle.
  541. pbDestRect = pbScan0 + (yTrg * lDestDelta) + xTrg;
  542. // Set the registers that can be set now for the operation.
  543. // SIGN_CACHE=1 and cuts 1 register from the setup.
  544. CHECK_FIFO_SPACE(pjBase, 7);
  545. // DWGCTL IDUMP+RPL+SRCCOPY+blockm_OFF+bltmod_BFCOL+patt_OFF+BG_OPAQUE
  546. // SGN 0
  547. // SHIFT 0
  548. // AR0 sea: ySrc*pitch + xSrc + cxTrg - 1
  549. // AR3 ssa: ySrc*pitch + xSrc
  550. // AR5 Screen pitch
  551. // FXLEFT 0
  552. // FXRIGHT cxTrg - 1
  553. // LEN cyTrg
  554. // xxMCTLWTST special value required by IDUMP bug fix
  555. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  556. {
  557. CP_WRITE(pjBase, DWG_SGN, 0);
  558. }
  559. // The SRC0-3 registers are trashed by the blt.
  560. ppdev->HopeFlags = SIGN_CACHE;
  561. CP_WRITE(pjBase, DWG_SHIFT, 0);
  562. CP_WRITE(pjBase, DWG_FXLEFT, 0);
  563. CP_WRITE(pjBase, DWG_AR5, ppdev->cxMemory);
  564. CP_WRITE(pjBase, DWG_LEN, cyTrg);
  565. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_IDUMP+atype_RPL+blockm_OFF+
  566. bop_SRCCOPY+bltmod_BFCOL+pattern_OFF+transc_BG_OPAQUE));
  567. // Recipe for IDUMP fix. We must break the IDUMP into a number of
  568. // smaller IDUMPS, according to the following formula:
  569. //
  570. // 0 < cx < 256 ==> cYSlice = int(1024/(cx << 2)) << 2 = int( 256/cx)<<2
  571. // 256 < cx < 1024 ==> cYSlice = int(4096/(cx << 2)) << 2 = int(1024/cx)<<2
  572. // 1024 < cx < 1600 ==> cYSlice = int(1600/(cx << 2)) << 2 = int(1600/cx)<<2
  573. //
  574. // We will modify it this way:
  575. //
  576. // 0 < cx <= 256 ==> cYSlice = int(1024/(cx << 2)) << 2 = int( 256/cx)<<2
  577. // 256 < cx <= 512 ==> cYSlice = int(4096/(cx << 2)) << 2 = int(1024/cx)<<2
  578. // 512 < cx ==> cYSlice = 4
  579. if (cxTrg > 512)
  580. {
  581. cySlice = 4;
  582. }
  583. else if (cxTrg > 256)
  584. {
  585. cySlice = (1024 / cxTrg) << 2;
  586. }
  587. else
  588. {
  589. cySlice = (256 / cxTrg) << 2;
  590. }
  591. // Number of bytes, padded to the next dword, to be moved per scanline.
  592. NbBytesPerScan = (cxTrg+3) & -4;
  593. NbDWords = NbBytesPerScan >> 2;
  594. pDW = (ULONG*) pbDestRect;
  595. // There will probably be a number of full slices (of height cySlice).
  596. // Source Start Address of the first slice.
  597. ulSSA = ySrc * ppdev->cxMemory + xSrc;
  598. ulSEA = ulSSA + cxTrg - 1;
  599. // Increment to get to the SSA of the next full slice.
  600. ulSSAIncrement = cySlice * ppdev->cxMemory;
  601. // Compute alignment parameters for the blt. We want to read the
  602. // minimum number of dwords from the screen, and we want to align
  603. // the write into memory on dword boundaries. We want to do it
  604. // this way:
  605. //
  606. // width -> 1 2 3 4 5 6 7
  607. // ---- ---- ---- ---- --------- -------------- --------------
  608. // xTrg&3
  609. // 1 ---0 --10 -210 3210 321- --10 321- -210 321- DWxx
  610. // 2 ---0 --10 -210 3210 32-- -210 32-- DWxx 32-- DWxx ---0
  611. // 3 ---0 --10 -210 3210 3--- DWxx 3--- DWxx ---0 3--- DWxx --10
  612. // 0 ---0 --10 -210 DWxx DWxx ---0 DWxx --10 DWxx -210
  613. //
  614. // where 0, 1, 2, or 3 means that the corresponding byte of the dword
  615. // that was read in is stored as a byte, and DWxx means that the dword
  616. // that was read in is stored as a dword.
  617. // Compute some useful values.
  618. xTrgAl = xTrg & 0x03; // 0, 1, 2, 3
  619. xTrgInvAl = (0x04 - xTrgAl) & 0x03; // 0, 3, 2, 1
  620. cxTrgAl = cxTrg - xTrgInvAl;
  621. if (cxTrgAl < 4)
  622. {
  623. // The width is really small, we will need at most 2 dwords per scan.
  624. // All the pixels will be stored as bytes.
  625. // On each scanline:
  626. lPreDWordBytes = cxTrg; // Nb of bytes defore the first dword
  627. lDWords = 0; // Nb of dwords to be stored
  628. lPostDWordBytes = 0; // Nb of bytes after the last dword.
  629. }
  630. else
  631. {
  632. // Pixels will be stored as bytes and dwords.
  633. lPreDWordBytes = xTrgInvAl;
  634. lDWords = cxTrgAl / 4;
  635. if((lPostDWordBytes = cxTrgAl & 3) == 0)
  636. {
  637. lPostDWordBytes = 4;
  638. lDWords--;
  639. }
  640. }
  641. if (cxTrg <= 4)
  642. {
  643. NbFirstBytes = cxTrg;
  644. bPreShift = 0;
  645. NbLastBytes = 0;
  646. NbDWordsPerScan = 1;
  647. }
  648. else
  649. {
  650. ulSSA -= xTrgAl;
  651. bPreShift = (BYTE)xTrgAl * 8;
  652. NbFirstBytes = 4 - xTrgAl;
  653. NbLastBytes = lPreDWordBytes - NbFirstBytes;
  654. NbDWordsPerScan = ((lPreDWordBytes + 3) / 4) + lDWords +
  655. ((lPostDWordBytes + 3) / 4);
  656. }
  657. CP_WRITE(pjBase, DWG_FXRIGHT, (bPreShift/8) + cxTrg - 1);
  658. // No index translation while copying.
  659. while ((cyTrg -= cySlice) >= 0)
  660. {
  661. // There is another full height slice to be read.
  662. vMgaGet8bppSliceFromScreen(ppdev, ulSSA, ulSEA,
  663. (ULONG) cySlice, NbDWordsPerScan,
  664. NbFirstBytes, NbLastBytes,
  665. lPreDWordBytes, lDWords,
  666. lPostDWordBytes, lDestDelta,
  667. bPreShift, &pDW);
  668. // Bump Source Start Address to the start of the next slice.
  669. ulSSA += ulSSAIncrement;
  670. ulSEA += ulSSAIncrement;
  671. }
  672. // Make cyTrg positive again, and read the last slice, if any.
  673. if ((cyTrg += cySlice) != 0)
  674. {
  675. // There is a last, partial slice to be read.
  676. vMgaGet8bppSliceFromScreen(ppdev, ulSSA, ulSEA,
  677. (ULONG) cyTrg, NbDWordsPerScan,
  678. NbFirstBytes, NbLastBytes,
  679. lPreDWordBytes, lDWords,
  680. lPostDWordBytes, lDestDelta,
  681. bPreShift, &pDW);
  682. }
  683. }