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.

484 lines
14 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: blt32.c
  3. *
  4. * This module contains the low-level blt functions that are specific to
  5. * 32bpp.
  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 vMgaPatRealize24bpp
  13. *
  14. \**************************************************************************/
  15. VOID vMgaPatRealize24bpp(
  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_BUCOL + pattern_OFF +
  39. transc_BG_OPAQUE + hcprs_SRC_24_BPP));
  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, 8); // Source width is 9
  54. CP_WRITE(pjBase, DWG_AR5, 32); // Source pitch is 32
  55. // I'm guessing that there was a hardware bug found with FXLEFT
  56. // or FXRIGHT being 32 or greater, because the old code does a
  57. // modulo 32 on 'x' for a reason:
  58. CP_WRITE(pjBase, DWG_FXLEFT, pbe->ulLeft);
  59. CP_WRITE(pjBase, DWG_FXRIGHT, pbe->ulLeft + 15);
  60. CP_WRITE(pjBase, DWG_YDST, pbe->ulYDst);
  61. CP_START(pjBase, DWG_PITCH, 32 + ylin_LINEARIZE_NOT);
  62. CHECK_FIFO_SPACE(pjBase, 32);
  63. ASSERTDD(ppdev->iBitmapFormat == BMF_24BPP,
  64. "Expect 24bpp packed pattern. You may have to change RealizeBrush");
  65. for (pulSrc = prb->aulPattern, i = 8; i != 0; i--, pulSrc += 6)
  66. {
  67. CP_WRITE_SRC(pjBase, *(pulSrc));
  68. CP_WRITE_SRC(pjBase, *(pulSrc + 1));
  69. CP_WRITE_SRC(pjBase, *(pulSrc + 2));
  70. CP_WRITE_SRC(pjBase, *(pulSrc + 3));
  71. CP_WRITE_SRC(pjBase, *(pulSrc + 4));
  72. CP_WRITE_SRC(pjBase, *(pulSrc + 5));
  73. // The pattern has to be 9 pixels wide, with an extra copy of
  74. // the first pixel:
  75. CP_WRITE_SRC(pjBase, *(pulSrc ));
  76. }
  77. // Don't forget to restore the pitch:
  78. CHECK_FIFO_SPACE(pjBase, 1);
  79. CP_WRITE(pjBase, DWG_PITCH, ppdev->cxMemory);
  80. }
  81. /******************************Public*Routine******************************\
  82. * VOID vMgaFillPat24bpp
  83. *
  84. \**************************************************************************/
  85. VOID vMgaFillPat24bpp( // Type FNFILL
  86. PDEV* ppdev,
  87. LONG c, // Can't be zero
  88. RECTL* prcl, // List of rectangles to be filled, in relative
  89. // coordinates
  90. ULONG rop4, // Rop4
  91. RBRUSH_COLOR rbc, // rbc.prb points to brush realization structure
  92. POINTL* pptlBrush) // Pattern alignment
  93. {
  94. BYTE* pjBase;
  95. BRUSHENTRY* pbe;
  96. LONG xOffset;
  97. LONG yOffset;
  98. CHAR cFifo;
  99. ULONG ulHwMix;
  100. LONG xLeft;
  101. LONG xRight;
  102. LONG yTop;
  103. LONG cx;
  104. LONG cy;
  105. LONG xBrush;
  106. LONG yBrush;
  107. ULONG ulLinear;
  108. LONG i;
  109. ASSERTDD(!(rbc.prb->fl & RBRUSH_2COLOR), "Can't do 2 colour brushes here");
  110. ASSERTDD((rbc.prb != NULL) && (rbc.prb->apbe[IBOARD(ppdev)] != NULL),
  111. "apbe[iBoard] should be initialized to &beUnrealizedBrush");
  112. // We have to ensure that no other brush took our spot in off-screen
  113. // memory, or we might have to realize the brush for the first time:
  114. pbe = rbc.prb->apbe[IBOARD(ppdev)];
  115. if (pbe->prbVerify != rbc.prb)
  116. {
  117. vMgaPatRealize24bpp(ppdev, rbc.prb);
  118. pbe = rbc.prb->apbe[IBOARD(ppdev)];
  119. }
  120. pjBase = ppdev->pjBase;
  121. xOffset = ppdev->xOffset;
  122. yOffset = ppdev->yOffset;
  123. do {
  124. cFifo = GET_FIFO_SPACE(pjBase) - 4;
  125. } while (cFifo < 0);
  126. if (rop4 == 0xf0f0) // PATCOPY
  127. {
  128. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RPL + blockm_OFF +
  129. trans_0 + bltmod_BUCOL + pattern_ON +
  130. transc_BG_OPAQUE + bop_SRCCOPY));
  131. }
  132. else
  133. {
  134. ulHwMix = (rop4 & 0x03) + ((rop4 & 0x30) >> 2);
  135. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_BITBLT + atype_RSTR + blockm_OFF +
  136. trans_0 + bltmod_BUCOL + pattern_ON +
  137. transc_BG_OPAQUE + (ulHwMix << 16)));
  138. }
  139. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  140. {
  141. CP_WRITE(pjBase, DWG_SGN, 0);
  142. }
  143. ppdev->HopeFlags = SIGN_CACHE;
  144. CP_WRITE(pjBase, DWG_SHIFT, 0);
  145. CP_WRITE(pjBase, DWG_AR5, 32);
  146. do {
  147. yTop = prcl->top;
  148. cy = prcl->bottom - yTop;
  149. xLeft = prcl->left;
  150. cx = prcl->right - xLeft - 1; // Note inclusiveness
  151. xBrush = (xLeft - pptlBrush->x) & 7;
  152. yBrush = (yTop - pptlBrush->y) & 7;
  153. ulLinear = pbe->ulLinear + (yBrush << 5);
  154. // Convert to absolute coordinates:
  155. xLeft += xOffset;
  156. yTop += yOffset;
  157. // Due to hardware limitations, we have to draw the rectangle
  158. // in four or five passes. On each pass, a maximum of two columns
  159. // of the brush can be drawn.
  160. if (xLeft & 1)
  161. {
  162. // It seems to be a hardware limitation that our passes always
  163. // to start on an even pixel when the width is more than one.
  164. // As such, do an initial strip of width one to align to an even
  165. // pixel:
  166. cFifo -= 6;
  167. while (cFifo < 0)
  168. {
  169. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  170. }
  171. CP_WRITE(pjBase, DWG_LEN, cy);
  172. CP_WRITE(pjBase, DWG_YDST, yTop);
  173. CP_WRITE(pjBase, DWG_AR3, ulLinear + xBrush);
  174. CP_WRITE(pjBase, DWG_AR0, ulLinear + xBrush + 3);
  175. CP_WRITE(pjBase, DWG_FXLEFT, xLeft);
  176. CP_START(pjBase, DWG_FXRIGHT, xLeft);
  177. xBrush = (xBrush + 1) & 7;
  178. xLeft++;
  179. cx--;
  180. if (cx < 0) // Recall inclusiveness
  181. continue;
  182. }
  183. i = 4;
  184. do {
  185. cFifo -= 6;
  186. while (cFifo < 0)
  187. {
  188. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  189. }
  190. CP_WRITE(pjBase, DWG_LEN, cy);
  191. CP_WRITE(pjBase, DWG_YDST, yTop);
  192. CP_WRITE(pjBase, DWG_AR3, ulLinear + xBrush);
  193. CP_WRITE(pjBase, DWG_AR0, ulLinear + xBrush + 3);
  194. CP_WRITE(pjBase, DWG_FXLEFT, xLeft);
  195. xRight = xLeft + (cx & ~7);
  196. if (cx & 7)
  197. xRight++;
  198. CP_START(pjBase, DWG_FXRIGHT, xRight);
  199. if (--i == 0)
  200. break;
  201. xBrush = (xBrush + 2) & 7;
  202. xLeft += 2;
  203. cx -= 2;
  204. } while (cx >= 0);
  205. } while (prcl++, --c != 0);
  206. }
  207. /******************************Public*Routine******************************\
  208. * VOID vMgaGetBits24bpp
  209. *
  210. * Reads the bits from the screen at 24bpp
  211. \**************************************************************************/
  212. VOID vMgaGetBits24bpp(
  213. PDEV* ppdev, // Current src pdev
  214. SURFOBJ* psoDst, // Destination surface for the color bits
  215. RECTL* prclDst, // Area to be modified within the dest surface,
  216. // in absolute coordinates
  217. POINTL* pptlSrc) // Upper left corner of source rectangle,
  218. // in absolute coordinates
  219. {
  220. BYTE* pjBase;
  221. BYTE* pbScan0;
  222. BYTE* pbDestRect;
  223. LONG xSrc, ySrc, xTrg, yTrg, cxTrg, cyTrg, lDestDelta;
  224. ULONG temp, ulSSA, ulSSAIncrement, HstStatus, AbortCnt;
  225. LONG i, NbDWords;
  226. ULONG* pulDest;
  227. ULONG* locpulDest;
  228. ULONG* pDMAWindow;
  229. pjBase = ppdev->pjBase;
  230. AbortCnt = 1000;
  231. // Calculate the size of the target rectangle, and pick up
  232. // some convenient locals.
  233. // Starting (x,y) and extents within the destination bitmap.
  234. // If an extent is 0 or negative, we don't have anything to do.
  235. cxTrg = prclDst->right - prclDst->left;
  236. cyTrg = prclDst->bottom - prclDst->top;
  237. xTrg = prclDst->left;
  238. yTrg = prclDst->top;
  239. ASSERTDD(cxTrg > 0 && cyTrg > 0, "Shouldn't get empty extents");
  240. // First scanline of the destination bitmap.
  241. pbScan0 = (BYTE*) psoDst->pvScan0;
  242. // Starting (x,y) on the screen.
  243. xSrc = pptlSrc->x;
  244. ySrc = pptlSrc->y;
  245. // Scan increment within the destination bitmap.
  246. lDestDelta = psoDst->lDelta;
  247. // Calculate the location of the destination rectangle.
  248. pbDestRect = pbScan0 + (yTrg * lDestDelta);
  249. pbDestRect += 3*xTrg;
  250. // Set the registers that can be set now for the operation.
  251. // SIGN_CACHE=1 and cuts 1 register from the setup.
  252. CHECK_FIFO_SPACE(pjBase, 7);
  253. // DWGCTL IDUMP+RPL+SRCCOPY+blockm_OFF+bltmod_BUCOL+patt_OFF+BG_OPAQUE
  254. // SGN 0
  255. // SHIFT 0
  256. // AR0 sea: ySrc*pitch + xSrc + cxTrg - 1
  257. // AR3 ssa: ySrc*pitch + xSrc
  258. // AR5 Screen pitch
  259. // FXLEFT 0
  260. // FXRIGHT cxTrg - 1
  261. // LEN cyTrg
  262. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  263. {
  264. CP_WRITE(pjBase, DWG_SGN, 0);
  265. ppdev->HopeFlags |= SIGN_CACHE;
  266. }
  267. CP_WRITE(pjBase, DWG_SHIFT, 0);
  268. CP_WRITE(pjBase, DWG_YDST, 0);
  269. CP_WRITE(pjBase, DWG_FXLEFT, 0);
  270. CP_WRITE(pjBase, DWG_FXRIGHT, (cxTrg - 1));
  271. CP_WRITE(pjBase, DWG_AR5, ppdev->cxMemory);
  272. // The SRC0-3 registers are trashed by the blt.
  273. ppdev->HopeFlags &= ~(ARX_CACHE | PATTERN_CACHE);
  274. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_IDUMP+atype_RPL+blockm_OFF+
  275. bop_SRCCOPY+bltmod_BUCOL+pattern_OFF+
  276. transc_BG_OPAQUE));
  277. // We won't have a full-speed routine, because we must read 32 bits per
  278. // pixel and either store only 24 bits (if the destination bitmap is
  279. // 24bpp), or mask out the eight msb's and then store 32 bits (if the
  280. // destination bitmap is 32bpp).
  281. // Source Start Address of the first slice.
  282. ulSSA = ySrc * ppdev->cxMemory + xSrc + ppdev->ulYDstOrg;
  283. // Increment to get to the SSA of the next scanline.
  284. ulSSAIncrement = ppdev->cxMemory;
  285. // Number of full dwords to be read within the loop on each scan.
  286. NbDWords = cxTrg - 1;
  287. pDMAWindow = (ULONG*) (ppdev->pjBase + DMAWND);
  288. locpulDest = (ULONG*) pbDestRect;
  289. // No color translation while copying.
  290. while (cyTrg-- > 0)
  291. {
  292. do {
  293. CHECK_FIFO_SPACE(pjBase, 3);
  294. // This is where we'll start storing data.
  295. pulDest = locpulDest;
  296. // Complete the IDUMP setup.
  297. CP_WRITE(pjBase, DWG_AR3, ulSSA);
  298. CP_WRITE(pjBase, DWG_AR0, ulSSA + cxTrg - 1);
  299. // Turn the pseudoDMA on.
  300. BLT_READ_ON(ppdev, pjBase);
  301. CP_START(pjBase, DWG_LEN, 1);
  302. // Make sure the setup is complete.
  303. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  304. if (NbDWords)
  305. {
  306. // There is at least one dword left to be read.
  307. // Copy a number of full dwords from the current scanline.
  308. for (i = 0; i < NbDWords; i++)
  309. {
  310. temp = CP_READ_DMA(ppdev, pDMAWindow);
  311. * ((UCHAR*)pulDest + 0) = (UCHAR) (temp);
  312. * ((UCHAR*)pulDest + 1) = (UCHAR) (temp >> 8);
  313. * ((UCHAR*)pulDest + 2) = (UCHAR) (temp >> 16);
  314. (UCHAR*)pulDest += 3;
  315. }
  316. }
  317. // Check for the EngineBusy flag.
  318. for (i = 0; i < 7; i++)
  319. {
  320. HstStatus = CP_READ_STATUS(pjBase);
  321. }
  322. if (HstStatus &= (dwgengsts_MASK >> 16))
  323. {
  324. // The drawing engine is still busy, while it should not be:
  325. // there was a problem with this slice.
  326. // Empty the DMA window.
  327. do {
  328. CP_READ_DMA(ppdev, pDMAWindow);
  329. // Check for the EngineBusy flag. If the engine is still
  330. // busy, then we'll have to read another dword.
  331. for (i = 0; i < 7; i++)
  332. {
  333. temp = CP_READ_STATUS(pjBase);
  334. }
  335. } while (temp & (dwgengsts_MASK >> 16));
  336. // The DMA window should now be empty.
  337. // We cannot check the HST_STATUS two lower bytes anymore,
  338. // so this is new.
  339. if (--AbortCnt > 0)
  340. {
  341. // Signal we'll have to do this again.
  342. HstStatus = 1;
  343. }
  344. else
  345. {
  346. // We tried hard enough, desist.
  347. HstStatus = 0;
  348. }
  349. }
  350. // The last dword to be read should be available now.
  351. temp = CP_READ_DMA(ppdev, pDMAWindow);
  352. * ((UCHAR*)pulDest + 0) = (UCHAR) (temp);
  353. * ((UCHAR*)pulDest + 1) = (UCHAR) (temp >> 8);
  354. * ((UCHAR*)pulDest + 2) = (UCHAR) (temp >> 16);
  355. // Turn the pseudoDMA off.
  356. BLT_READ_OFF(ppdev, pjBase);
  357. // Redo the whole thing if there was a problem with this slice.
  358. } while (HstStatus);
  359. // We're done with the current scanline, deal with the next one.
  360. (UCHAR*) locpulDest += lDestDelta;
  361. ulSSA += ulSSAIncrement;
  362. }
  363. }