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.

1233 lines
38 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: bank.c
  3. *
  4. * Contains all the banking code for the display driver.
  5. *
  6. * It's helpful not to have to implement all the DDI drawing functionality
  7. * in a driver (who wants to write the code to support true ROP4's with
  8. * arbitrary sized patterns?). Fortunately, we can punt to GDI for any
  9. * drawing we don't want to do. And if GDI can write directly on the frame
  10. * buffer bits, performance won't even be toooo bad.
  11. *
  12. * NT's GDI can draw on any standard format frame buffer. When the entire
  13. * frame buffer can be mapped into main memory, it's very simple to set up:
  14. * the display driver tells GDI the frame buffer format and location, and
  15. * GDI can then just draw directly.
  16. *
  17. * When only one bank of the frame buffer can be mapped into main memory
  18. * at one time (e.g., there is a moveable 64k aperture) things are not
  19. * nearly so easy. For every bank spanned by a drawing operation, we have
  20. * to set the hardware to the bank, and call back to GDI. We tell GDI
  21. * to draw only on the mapped-in bank by mucking with the drawing call's
  22. * CLIPOBJ.
  23. *
  24. * This module contains the code for doing all banking support.
  25. *
  26. * This code supports 8, 16 and 32bpp colour depths, arbitrary bank
  27. * sizes, and handles 'broken rasters' (which happens when the bank size
  28. * is not a multiple of the scan length; some scans will end up being
  29. * split over two separate banks).
  30. *
  31. * Note: If you mess with this code and break it, you can expect to get
  32. * random access violations on call-backs in internal GDI routines
  33. * that are very hard to debug.
  34. *
  35. * Copyright (c) 1993-1995 Microsoft Corporation
  36. \**************************************************************************/
  37. #include "precomp.h"
  38. typedef struct _BANKDATA {
  39. ULONG nothing_yet;
  40. } BANKDATA; /* bd, pbd */
  41. ////////////////////////////////////////////////////////////////////////////
  42. // Banking code
  43. //
  44. VOID vBankSelectMode(
  45. PPDEV ppdev,
  46. BANK_MODE bankm)
  47. {
  48. // BANK_ENABLE - We've exited full-screen; re-enable banking
  49. // BANK_ON - We're about to use the memory aperture
  50. // BANK_OFF - We've finished using the memory aperture
  51. // BANK_DISABLE - We're about to enter full-screen; shut down banking
  52. switch(bankm){
  53. case BANK_ENABLE: DISPDBG((115,"vBankSelectMode(BANK_ENABLE)"));
  54. break;
  55. case BANK_ON: DISPDBG((115,"vBankSelectMode(BANK_ON)"));
  56. //
  57. // [BUGFIX] - I don't know why, but the CL542x
  58. // needs the color register set to
  59. // 0 when drawing to the framebuffer
  60. //
  61. if (ppdev->flCaps & CAPS_MM_IO)
  62. {
  63. CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, ppdev->pjBase);
  64. CP_MM_FG_COLOR(ppdev, ppdev->pjBase, 0);
  65. }
  66. else
  67. {
  68. CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, ppdev->pjPorts);
  69. CP_IO_FG_COLOR(ppdev, ppdev->pjPorts, 0);
  70. }
  71. CP_EIEIO();
  72. break;
  73. case BANK_OFF: DISPDBG((115,"vBankSelectMode(BANK_OFF)"));
  74. break;
  75. case BANK_DISABLE: DISPDBG((115,"vBankSelectMode(BANK_DISABLE)"));
  76. break;
  77. default: DISPDBG((115,"vBankSelectMode(UNKNOWN=%d)", bankm));
  78. RIP("Bad BANK_MODE selected");
  79. break;
  80. }
  81. }
  82. VOID vBankMap(
  83. PPDEV ppdev,
  84. LONG iBank)
  85. {
  86. WORD w;
  87. //
  88. // map the segement to iBank
  89. //
  90. DISPDBG((10,"vBankMap(iBank=%d)", iBank));
  91. w = (WORD) (0x9 | (iBank << ppdev->ulBankShiftFactor));
  92. CP_OUT_WORD(ppdev->pjPorts,INDEX_REG,w);
  93. CP_EIEIO();
  94. }
  95. VOID vBankInitialize(
  96. PPDEV ppdev,
  97. BOOL bMmIo)
  98. {
  99. }
  100. /******************************Public*Routine******************************\
  101. * BOOL bEnableBanking
  102. *
  103. \**************************************************************************/
  104. BOOL bEnableBanking(
  105. PDEV* ppdev)
  106. {
  107. CLIPOBJ* pcoBank;
  108. SURFOBJ* psoBank;
  109. SIZEL sizl;
  110. HSURF hsurf;
  111. static FNBANKINITIALIZE* pfnBankInitialize;
  112. LONG lDelta;
  113. LONG cjBank;
  114. LONG cPower2;
  115. // This routine may be called multiple times (e.g., each time
  116. // full-screen is exited), so make sure we do any allocations
  117. // only once:
  118. if (ppdev->pcoBank == NULL)
  119. {
  120. // Create a temporary clip object that we'll use for the bank
  121. // when we're given a Null or DC_TRIVIAL clip object:
  122. pcoBank = EngCreateClip();
  123. if (pcoBank == NULL)
  124. goto ReturnFalse;
  125. // We break every per-bank GDI call-back into simple rectangles:
  126. pcoBank->iDComplexity = DC_RECT;
  127. pcoBank->fjOptions = OC_BANK_CLIP;
  128. // Create a GDI surface that we'll wrap around our bank in
  129. // call-backs:
  130. sizl.cx = ppdev->cxMemory;
  131. sizl.cy = ppdev->cyMemory;
  132. hsurf = (HSURF) EngCreateBitmap(sizl,
  133. ppdev->lDelta,
  134. ppdev->iBitmapFormat,
  135. BMF_TOPDOWN,
  136. ppdev->pjScreen);
  137. // Note that we hook zero calls -- after all, the entire point
  138. // of all this is to have GDI do all the drawing on the bank.
  139. // Once we're done the association, we can leave the surface
  140. // permanently locked:
  141. if ((hsurf == 0) ||
  142. (!EngAssociateSurface(hsurf, ppdev->hdevEng, 0)) ||
  143. (!(psoBank = EngLockSurface(hsurf))))
  144. {
  145. DISPDBG((0, "Failed wrapper surface creation"));
  146. EngDeleteSurface(hsurf);
  147. EngDeleteClip(pcoBank);
  148. goto ReturnFalse;
  149. }
  150. ppdev->pcoBank = pcoBank;
  151. ppdev->psoBank = psoBank;
  152. ppdev->pvBankData = &ppdev->aulBankData[0];
  153. DISPDBG((2, "pcoBank = %x", pcoBank));
  154. DISPDBG((2, "psoBank = %x", psoBank));
  155. ppdev->pfnBankMap = vBankMap;
  156. ppdev->pfnBankSelectMode = vBankSelectMode;
  157. pfnBankInitialize = vBankInitialize;
  158. lDelta = ppdev->lDelta;
  159. cjBank = ppdev->cjBank;
  160. ASSERTDD(lDelta > 0, "Bad things happen with negative lDeltas");
  161. ASSERTDD(cjBank > lDelta, "Worse things happen with bad bank sizes");
  162. if (((lDelta & (lDelta - 1)) != 0) || ((cjBank & (cjBank - 1)) != 0))
  163. {
  164. // When either the screen stride or the bank size is not a power
  165. // of two, we have to use the slower 'bBankComputeNonPower2'
  166. // function for bank calculations, 'cause there can be broken
  167. // rasters and stuff:
  168. ppdev->pfnBankCompute = bBankComputeNonPower2;
  169. }
  170. else
  171. {
  172. // We can use the super duper fast bank calculator. Yippie,
  173. // yahoo! (I am easily amused.)
  174. cPower2 = 0;
  175. while (cjBank != lDelta)
  176. {
  177. cjBank >>= 1;
  178. cPower2++;
  179. }
  180. // We've just calculated that cjBank / lDelta = 2 ^ cPower2:
  181. ppdev->cPower2ScansPerBank = cPower2;
  182. while (cjBank != 1)
  183. {
  184. cjBank >>= 1;
  185. cPower2++;
  186. }
  187. // Continuing on, we've calculated that cjBank = 2 ^ cPower2:
  188. ppdev->cPower2BankSizeInBytes = cPower2;
  189. ppdev->pfnBankCompute = bBankComputePower2;
  190. }
  191. }
  192. // Warm up the hardware:
  193. pfnBankInitialize(ppdev, FALSE);
  194. ppdev->pfnBankSelectMode(ppdev, BANK_ENABLE);
  195. DISPDBG((5, "Passed bEnableBanking"));
  196. return(TRUE);
  197. ReturnFalse:
  198. DISPDBG((0, "Failed bEnableBanking!"));
  199. return(FALSE);
  200. }
  201. /******************************Public*Routine******************************\
  202. * VOID vDisableBanking
  203. *
  204. \**************************************************************************/
  205. VOID vDisableBanking(PDEV* ppdev)
  206. {
  207. HSURF hsurf;
  208. if (ppdev->psoBank != NULL)
  209. {
  210. hsurf = ppdev->psoBank->hsurf;
  211. EngUnlockSurface(ppdev->psoBank);
  212. EngDeleteSurface(hsurf);
  213. }
  214. if (ppdev->pcoBank != NULL)
  215. EngDeleteClip(ppdev->pcoBank);
  216. }
  217. /******************************Public*Routine******************************\
  218. * VOID vAssertModeBanking
  219. *
  220. \**************************************************************************/
  221. VOID vAssertModeBanking(
  222. PDEV* ppdev,
  223. BOOL bEnable)
  224. {
  225. // Inform the miniport bank code about the change in state:
  226. ppdev->pfnBankSelectMode(ppdev,
  227. bEnable ? BANK_ENABLE : BANK_DISABLE);
  228. }
  229. /******************************Public*Routine******************************\
  230. * BOOL bBankComputeNonPower2
  231. *
  232. * Given the bounds of the drawing operation described by 'prclDraw',
  233. * computes the bank number and rectangle bounds for the first engine
  234. * call back.
  235. *
  236. * Returns the bank number, 'prclBank' is the bounds for the first
  237. * call-back, and 'pcjOffset' is the adjustment for 'pvScan0'.
  238. *
  239. * This routine does a couple of divides for the bank calculation. We
  240. * don't use a look-up table for banks because it's not straight forward
  241. * to use with broken rasters, and with large amounts of video memory
  242. * and small banks, the tables could get large. We'd probably use it
  243. * infrequently enough that the memory manager would be swapping it
  244. * in and out whenever we touched it.
  245. *
  246. * Returns TRUE if prclDraw is entirely contained in one bank; FALSE if
  247. * prclDraw spans multiple banks.
  248. *
  249. \**************************************************************************/
  250. BOOL bBankComputeNonPower2( // Type FNBANKCOMPUTE
  251. PDEV* ppdev,
  252. RECTL* prclDraw, // Extents of drawing operation, in absolute
  253. // coordinates
  254. RECTL* prclBank, // Returns bounds of drawing operation for this
  255. // bank, in absolute coordinates
  256. LONG* pcjOffset, // Returns the byte offset for this bank
  257. LONG* piBank) // Returns the bank number
  258. {
  259. LONG cjBufferOffset;
  260. LONG iBank;
  261. LONG cjBank;
  262. LONG cjBankOffset;
  263. LONG cjBankRemainder;
  264. LONG cjScan;
  265. LONG cScansInBank;
  266. LONG cjScanRemainder;
  267. LONG lDelta;
  268. BOOL bOneBank;
  269. bOneBank = FALSE;
  270. lDelta = ppdev->lDelta;
  271. cjBufferOffset = prclDraw->top * lDelta
  272. + PELS_TO_BYTES(prclDraw->left);
  273. cjBank = ppdev->cjBank;
  274. // iBank = cjBufferOffset / cjBank;
  275. // cjBankOffset = cjBufferOffset % cjBank;
  276. QUOTIENT_REMAINDER(cjBufferOffset, cjBank, iBank, cjBankOffset);
  277. *piBank = iBank;
  278. *pcjOffset = iBank * cjBank;
  279. cjBankRemainder = cjBank - cjBankOffset;
  280. cjScan = PELS_TO_BYTES(prclDraw->right - prclDraw->left);
  281. if (cjBankRemainder < cjScan)
  282. {
  283. // Oh no, we've got a broken raster!
  284. prclBank->left = prclDraw->left;
  285. prclBank->right = prclDraw->left +
  286. BYTES_TO_PELS(cjBankRemainder);
  287. prclBank->top = prclDraw->top;
  288. prclBank->bottom = prclDraw->top + 1;
  289. }
  290. else
  291. {
  292. // cScansInBank = cjBankRemainder / lDelta;
  293. // cjScanRemainder = cjBankRemainder % lDelta;
  294. ASSERTDD(lDelta > 0, "We assume positive lDelta here");
  295. QUOTIENT_REMAINDER(cjBankRemainder, lDelta,
  296. cScansInBank, cjScanRemainder);
  297. if (cjScanRemainder >= cjScan)
  298. {
  299. // The bottom scan of the bank may be broken, but it breaks after
  300. // any drawing we'll be doing on that scan. So we can simply
  301. // add the scan to this bank:
  302. cScansInBank++;
  303. }
  304. prclBank->left = prclDraw->left;
  305. prclBank->right = prclDraw->right;
  306. prclBank->top = prclDraw->top;
  307. prclBank->bottom = prclDraw->top + cScansInBank;
  308. if (prclBank->bottom >= prclDraw->bottom)
  309. {
  310. prclBank->bottom = prclDraw->bottom;
  311. bOneBank = TRUE;
  312. }
  313. }
  314. return(bOneBank);
  315. }
  316. /******************************Public*Routine******************************\
  317. * BOOL bBankComputePower2
  318. *
  319. * Functions the same as 'bBankComputeNonPower2', except that it is
  320. * an accelerated special case for when both the screen stride and bank
  321. * size are powers of 2.
  322. *
  323. \**************************************************************************/
  324. BOOL bBankComputePower2( // Type FNBANKCOMPUTE
  325. PDEV* ppdev,
  326. RECTL* prclDraw, // Extents of drawing operation, in absolute
  327. // coordinates
  328. RECTL* prclBank, // Returns bounds of drawing operation for this
  329. // bank, in absolute coordinates
  330. LONG* pcjOffset, // Returns the byte offset for this bank
  331. LONG* piBank) // Returns the bank number
  332. {
  333. LONG iBank;
  334. LONG yTopNextBank;
  335. BOOL bOneBank;
  336. iBank = prclDraw->top >> ppdev->cPower2ScansPerBank;
  337. yTopNextBank = (iBank + 1) << ppdev->cPower2ScansPerBank;
  338. *piBank = iBank;
  339. *pcjOffset = iBank << ppdev->cPower2BankSizeInBytes;
  340. prclBank->left = prclDraw->left;
  341. prclBank->right = prclDraw->right;
  342. prclBank->top = prclDraw->top;
  343. prclBank->bottom = yTopNextBank;
  344. bOneBank = FALSE;
  345. if (prclBank->bottom >= prclDraw->bottom)
  346. {
  347. prclBank->bottom = prclDraw->bottom;
  348. bOneBank = TRUE;
  349. }
  350. return(bOneBank);
  351. }
  352. /******************************Public*Routine******************************\
  353. * VOID vBankStart
  354. *
  355. * Given the bounds of the drawing operation described by 'prclDraw' and
  356. * the original clip object, maps in the first bank and returns in
  357. * 'pbnk->pco' and 'pbnk->pso' the CLIPOBJ and SURFOBJ to be passed to the
  358. * engine for the first banked call-back.
  359. *
  360. * Note: This routine only supports the screen being the destination, and
  361. * not the source. We have a separate, faster routine for doing
  362. * SRCCOPY reads from the screen, so it isn't worth the extra code
  363. * size to implement.
  364. *
  365. \**************************************************************************/
  366. VOID vBankStart(
  367. PDEV* ppdev, // Physical device information.
  368. RECTL* prclDraw, // Rectangle bounding the draw area, in relative
  369. // coordinates. Note that 'left' and 'right'
  370. // should be set for correct handling with broken
  371. // rasters.
  372. CLIPOBJ* pco, // Original drawing clip object (may be modified).
  373. BANK* pbnk) // Resulting bank information.
  374. {
  375. LONG cjOffset;
  376. LONG xOffset;
  377. LONG yOffset;
  378. LONG xyOffset;
  379. DISPDBG((3, "vBankStart"));
  380. xOffset = ppdev->xOffset;
  381. yOffset = ppdev->yOffset;
  382. xyOffset = ppdev->xyOffset;
  383. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  384. {
  385. pco = ppdev->pcoBank;
  386. // Reset the clipping flag to trivial because we may have left
  387. // it as rectangular in a previous call:
  388. pco->iDComplexity = DC_TRIVIAL;
  389. // At the same time we convert to absolute coordinates, make sure
  390. // we won't try to enumerate past the bounds of the screen:
  391. pbnk->rclDraw.left = prclDraw->left + xOffset;
  392. pbnk->rclDraw.right = prclDraw->right + xOffset;
  393. pbnk->rclDraw.top
  394. = max(0, prclDraw->top + yOffset);
  395. pbnk->rclDraw.bottom
  396. = min(ppdev->cyMemory, prclDraw->bottom + yOffset);
  397. }
  398. else
  399. {
  400. pbnk->rclSaveBounds = pco->rclBounds;
  401. pbnk->iSaveDComplexity = pco->iDComplexity;
  402. pbnk->fjSaveOptions = pco->fjOptions;
  403. // Let GDI know that it has to pay attention to the clip object:
  404. pco->fjOptions |= OC_BANK_CLIP;
  405. // We have to honour the original clip object's rclBounds, so
  406. // intersect the drawing region with it, then convert to absolute
  407. // coordinates:
  408. pbnk->rclDraw.left
  409. = max(prclDraw->left, pco->rclBounds.left) + xOffset;
  410. pbnk->rclDraw.right
  411. = min(prclDraw->right, pco->rclBounds.right) + xOffset;
  412. pbnk->rclDraw.top
  413. = max(prclDraw->top, pco->rclBounds.top) + yOffset;
  414. pbnk->rclDraw.bottom
  415. = min(prclDraw->bottom, pco->rclBounds.bottom) + yOffset;
  416. }
  417. if ((pbnk->rclDraw.left > pbnk->rclDraw.right)
  418. || (pbnk->rclDraw.top > pbnk->rclDraw.bottom))
  419. {
  420. // It's conceivable that we could get a situation where we have
  421. // an empty draw rectangle. Make sure we won't puke on our shoes:
  422. pbnk->rclDraw.left = 0;
  423. pbnk->rclDraw.right = 0;
  424. pbnk->rclDraw.top = 0;
  425. pbnk->rclDraw.bottom = 0;
  426. }
  427. if (!ppdev->pfnBankCompute(ppdev, &pbnk->rclDraw, &pco->rclBounds,
  428. &cjOffset, &pbnk->iBank))
  429. {
  430. // The drawing operation spans multiple banks. If the original
  431. // clip object was marked as trivial, we have to make sure to
  432. // change it to rectangular so that GDI knows to pay attention
  433. // to the bounds of the bank:
  434. if (pco->iDComplexity == DC_TRIVIAL)
  435. pco->iDComplexity = DC_RECT;
  436. }
  437. pbnk->ppdev = ppdev;
  438. pbnk->pco = pco;
  439. pbnk->pso = ppdev->psoBank;
  440. // Convert rclBounds and pvScan0 from absolute coordinates back to
  441. // relative. When GDI calculates where to start drawing, it computes
  442. // pjDst = pso->pvScan0 + y * pso->lDelta + PELS_TO_BYTES(x), where 'x'
  443. // and 'y' are relative coordinates. We'll muck with pvScan0 to get
  444. // it pointing to the correct spot in the bank:
  445. pbnk->pso->pvScan0 = (ppdev->pjScreen - cjOffset) + xyOffset;
  446. pbnk->pso->lDelta = ppdev->lDelta; // Other functions muck with this value
  447. ASSERTDD((((ULONG_PTR) pbnk->pso->pvScan0) & 3) == 0,
  448. "Off-screen bitmaps must be dword aligned");
  449. pco->rclBounds.left -= xOffset;
  450. pco->rclBounds.right -= xOffset;
  451. pco->rclBounds.top -= yOffset;
  452. pco->rclBounds.bottom -= yOffset;
  453. // Enable banking and map in bank iBank:
  454. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  455. ppdev->pfnBankMap(ppdev, pbnk->iBank);
  456. }
  457. /******************************Public*Routine******************************\
  458. * BOOL bBankEnum
  459. *
  460. * If there is another bank to be drawn on, maps in the bank and returns
  461. * TRUE and the CLIPOBJ and SURFOBJ to be passed in the banked call-back.
  462. *
  463. * If there were no more banks to be drawn, returns FALSE.
  464. *
  465. \**************************************************************************/
  466. BOOL bBankEnum(
  467. BANK* pbnk)
  468. {
  469. LONG iBank;
  470. LONG cjOffset;
  471. PDEV* ppdev;
  472. CLIPOBJ* pco;
  473. LONG xOffset;
  474. LONG yOffset;
  475. DISPDBG((3, "vBankEnum"));
  476. ppdev = pbnk->ppdev;
  477. pco = pbnk->pco;
  478. xOffset = ppdev->xOffset;
  479. yOffset = ppdev->yOffset;
  480. // We check here to see if we have to handle the second part of
  481. // a broken raster. Recall that pbnk->rclDraw is in absolute
  482. // coordinates, but pco->rclBounds is in relative coordinates:
  483. if (pbnk->rclDraw.right - xOffset != pco->rclBounds.right)
  484. {
  485. // The clip object's 'top' and 'bottom' are already correct:
  486. pco->rclBounds.left = pco->rclBounds.right;
  487. pco->rclBounds.right = pbnk->rclDraw.right - xOffset;
  488. pbnk->pso->pvScan0 = (BYTE*) pbnk->pso->pvScan0 - ppdev->cjBank;
  489. pbnk->iBank++;
  490. ppdev->pfnBankMap(ppdev, pbnk->iBank);
  491. return(TRUE);
  492. }
  493. if (pbnk->rclDraw.bottom > pco->rclBounds.bottom + yOffset)
  494. {
  495. // Advance the drawing area 'top' to account for the bank we've
  496. // just finished, and map in the new bank:
  497. pbnk->rclDraw.top = pco->rclBounds.bottom + yOffset;
  498. ppdev->pfnBankCompute(ppdev, &pbnk->rclDraw, &pco->rclBounds,
  499. &cjOffset, &iBank);
  500. // Convert rclBounds back from absolute to relative coordinates:
  501. pco->rclBounds.left -= xOffset;
  502. pco->rclBounds.right -= xOffset;
  503. pco->rclBounds.top -= yOffset;
  504. pco->rclBounds.bottom -= yOffset;
  505. // If we just finished handling a broken raster, we've already
  506. // got the bank mapped in:
  507. if (iBank != pbnk->iBank)
  508. {
  509. pbnk->iBank = iBank;
  510. pbnk->pso->pvScan0 = (BYTE*) pbnk->pso->pvScan0 - ppdev->cjBank;
  511. ppdev->pfnBankMap(ppdev, iBank);
  512. }
  513. return(TRUE);
  514. }
  515. // We're done! Turn off banking and reset the clip object if necessary:
  516. ppdev->pfnBankSelectMode(ppdev, BANK_OFF);
  517. if (pco != ppdev->pcoBank)
  518. {
  519. pco->rclBounds = pbnk->rclSaveBounds;
  520. pco->iDComplexity = pbnk->iSaveDComplexity;
  521. pco->fjOptions = pbnk->fjSaveOptions;
  522. }
  523. return(FALSE);
  524. }
  525. /******************************Public*Routine******************************\
  526. * VOID vAlignedCopy
  527. *
  528. * Copies the given portion of a bitmap, using dword alignment for the
  529. * screen. Note that this routine has no notion of banking.
  530. *
  531. * Updates ppjDst and ppjSrc to point to the beginning of the next scan.
  532. *
  533. \**************************************************************************/
  534. VOID vAlignedCopy(
  535. PDEV* ppdev,
  536. BYTE** ppjDst,
  537. LONG lDstDelta,
  538. BYTE** ppjSrc,
  539. LONG lSrcDelta,
  540. LONG cjScan,
  541. LONG cyScan,
  542. BOOL bDstIsScreen)
  543. {
  544. BYTE* pjDst;
  545. BYTE* pjSrc;
  546. LONG cjMiddle;
  547. LONG culMiddle;
  548. LONG cjStartPhase;
  549. LONG cjEndPhase;
  550. pjSrc = *ppjSrc;
  551. pjDst = *ppjDst;
  552. cjStartPhase = (ULONG)((0 - ((bDstIsScreen) ? (ULONG_PTR)pjDst
  553. : (ULONG_PTR)pjSrc)) & 3);
  554. cjMiddle = cjScan - cjStartPhase;
  555. if (cjMiddle < 0)
  556. {
  557. cjStartPhase = 0;
  558. cjMiddle = cjScan;
  559. }
  560. lSrcDelta -= cjScan;
  561. lDstDelta -= cjScan; // Account for middle
  562. cjEndPhase = cjMiddle & 3;
  563. culMiddle = cjMiddle >> 2;
  564. if (DIRECT_ACCESS(ppdev))
  565. {
  566. LONG i;
  567. ///////////////////////////////////////////////////////////////////
  568. // Portable bus-aligned copy
  569. //
  570. // 'memcpy' usually aligns to the destination, so we could call
  571. // it for that case, but unfortunately we can't be sure. We
  572. // always want to align to the frame buffer:
  573. if (bDstIsScreen)
  574. {
  575. // Align to the destination (implying that the source may be
  576. // unaligned):
  577. for (; cyScan > 0; cyScan--)
  578. {
  579. for (i = cjStartPhase; i > 0; i--)
  580. {
  581. *pjDst++ = *pjSrc++;
  582. }
  583. for (i = culMiddle; i > 0; i--)
  584. {
  585. *((ULONG*) pjDst) = *((ULONG UNALIGNED *) pjSrc);
  586. pjSrc += sizeof(ULONG);
  587. pjDst += sizeof(ULONG);
  588. }
  589. for (i = cjEndPhase; i > 0; i--)
  590. {
  591. *pjDst++ = *pjSrc++;
  592. }
  593. pjSrc += lSrcDelta;
  594. pjDst += lDstDelta;
  595. }
  596. }
  597. else
  598. {
  599. // Align to the source (implying that the destination may be
  600. // unaligned):
  601. for (; cyScan > 0; cyScan--)
  602. {
  603. for (i = cjStartPhase; i > 0; i--)
  604. {
  605. *pjDst++ = *pjSrc++;
  606. }
  607. for (i = culMiddle; i > 0; i--)
  608. {
  609. *((ULONG UNALIGNED *) pjDst) = *((ULONG*) (pjSrc));
  610. pjSrc += sizeof(ULONG);
  611. pjDst += sizeof(ULONG);
  612. }
  613. for (i = cjEndPhase; i > 0; i--)
  614. {
  615. *pjDst++ = *pjSrc++;
  616. }
  617. pjSrc += lSrcDelta;
  618. pjDst += lDstDelta;
  619. }
  620. }
  621. *ppjSrc = pjSrc; // Save the updated pointers
  622. *ppjDst = pjDst;
  623. }
  624. #if !defined(_X86_)
  625. else
  626. {
  627. LONG i;
  628. ///////////////////////////////////////////////////////////////////
  629. // No direct dword reads bus-aligned copy
  630. //
  631. // We go through this code path if doing dword reads would
  632. // crash a non-x86 system.
  633. MEMORY_BARRIER();
  634. if (bDstIsScreen)
  635. {
  636. // Align to the destination (implying that the source may be
  637. // unaligned):
  638. for (; cyScan > 0; cyScan--)
  639. {
  640. for (i = cjStartPhase; i > 0; i--)
  641. {
  642. WRITE_REGISTER_UCHAR(pjDst, *pjSrc);
  643. pjSrc++;
  644. pjDst++;
  645. }
  646. for (i = culMiddle; i > 0; i--)
  647. {
  648. WRITE_REGISTER_ULONG(pjDst, *((ULONG UNALIGNED *) pjSrc));
  649. pjSrc += sizeof(ULONG);
  650. pjDst += sizeof(ULONG);
  651. }
  652. for (i = cjEndPhase; i > 0; i--)
  653. {
  654. WRITE_REGISTER_UCHAR(pjDst, *pjSrc);
  655. pjSrc++;
  656. pjDst++;
  657. }
  658. pjSrc += lSrcDelta;
  659. pjDst += lDstDelta;
  660. }
  661. }
  662. else
  663. {
  664. // Align to the source (implying that the destination may be
  665. // unaligned):
  666. for (; cyScan > 0; cyScan--)
  667. {
  668. for (i = cjStartPhase; i > 0; i--)
  669. {
  670. *pjDst = READ_REGISTER_UCHAR(pjSrc);
  671. pjSrc++;
  672. pjDst++;
  673. }
  674. for (i = culMiddle; i > 0; i--)
  675. {
  676. *((ULONG UNALIGNED *) pjDst) = READ_REGISTER_ULONG(pjSrc);
  677. pjSrc += sizeof(ULONG);
  678. pjDst += sizeof(ULONG);
  679. }
  680. for (i = cjEndPhase; i > 0; i--)
  681. {
  682. *pjDst = READ_REGISTER_UCHAR(pjSrc);
  683. pjSrc++;
  684. pjDst++;
  685. }
  686. pjSrc += lSrcDelta;
  687. pjDst += lDstDelta;
  688. }
  689. }
  690. *ppjSrc = pjSrc; // Save the updated pointers
  691. *ppjDst = pjDst;
  692. }
  693. #endif
  694. }
  695. /******************************Public*Routine******************************\
  696. * VOID vPutBits
  697. *
  698. * Copies the bits from the given surface to the screen, using the memory
  699. * aperture. Must be pre-clipped.
  700. *
  701. \**************************************************************************/
  702. VOID vPutBits(
  703. PDEV* ppdev,
  704. SURFOBJ* psoSrc,
  705. RECTL* prclDst, // Absolute coordinates!
  706. POINTL* pptlSrc) // Absolute coordinates!
  707. {
  708. RECTL rclDraw;
  709. RECTL rclBank;
  710. LONG iBank;
  711. LONG cjOffset;
  712. LONG cyScan;
  713. LONG lDstDelta;
  714. LONG lSrcDelta;
  715. BYTE* pjDst;
  716. BYTE* pjSrc;
  717. LONG cjScan;
  718. LONG iNewBank;
  719. LONG cjRemainder;
  720. BYTE* pjPorts = ppdev->pjPorts;
  721. // We need a local copy of 'rclDraw' because we'll be iteratively
  722. // modifying 'top' and passing the modified rectangle back into
  723. // bBankComputeNonPower2:
  724. DISPDBG((5, "vPutBits -- enter"));
  725. rclDraw = *prclDst;
  726. ASSERTDD((rclDraw.left >= 0) &&
  727. (rclDraw.top >= 0) &&
  728. (rclDraw.right <= ppdev->cxMemory) &&
  729. (rclDraw.bottom <= ppdev->cyMemory),
  730. "Rectangle wasn't fully clipped");
  731. // Compute the first bank, enable banking, then map in iBank:
  732. ppdev->pfnBankCompute(ppdev, &rclDraw, &rclBank, &cjOffset, &iBank);
  733. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  734. ppdev->pfnBankMap(ppdev, iBank);
  735. // Calculate the pointer to the upper-left corner of both rectangles:
  736. lDstDelta = ppdev->lDelta;
  737. pjDst = ppdev->pjScreen + rclDraw.top * lDstDelta
  738. + PELS_TO_BYTES(rclDraw.left)
  739. - cjOffset;
  740. lSrcDelta = psoSrc->lDelta;
  741. pjSrc = (BYTE*) psoSrc->pvScan0 + pptlSrc->y * lSrcDelta
  742. + PELS_TO_BYTES(pptlSrc->x);
  743. while (TRUE)
  744. {
  745. cjScan = PELS_TO_BYTES(rclBank.right - rclBank.left);
  746. cyScan = (rclBank.bottom - rclBank.top);
  747. vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
  748. TRUE); // Screen is the destination
  749. if (rclDraw.right != rclBank.right)
  750. {
  751. // Handle the second part of the broken raster:
  752. iBank++;
  753. ppdev->pfnBankMap(ppdev, iBank);
  754. // Number of bytes we've yet to do on the broken scan:
  755. cjRemainder = PELS_TO_BYTES(rclDraw.right - rclBank.right);
  756. // Account for the fact that we're now one bank lower in the
  757. // destination:
  758. pjDst -= ppdev->cjBank;
  759. // Implicitly back up the source and destination pointers to the
  760. // unfinished portion of the scan:
  761. if (DIRECT_ACCESS(ppdev))
  762. {
  763. memcpy(pjDst + (cjScan - lDstDelta),
  764. pjSrc + (cjScan - lSrcDelta),
  765. cjRemainder);
  766. }
  767. else
  768. {
  769. BYTE* pjTmpDst = pjDst + (cjScan - lDstDelta);
  770. BYTE* pjTmpSrc = pjSrc + (cjScan - lSrcDelta);
  771. vAlignedCopy(ppdev, &pjTmpDst, 0, &pjTmpSrc, 0, cjRemainder, 1,
  772. TRUE); // Screen is the destination
  773. }
  774. }
  775. if (rclDraw.bottom > rclBank.bottom)
  776. {
  777. rclDraw.top = rclBank.bottom;
  778. ppdev->pfnBankCompute(ppdev, &rclDraw, &rclBank, &cjOffset,
  779. &iNewBank);
  780. // If we just handled the second part of a broken raster,
  781. // then we've already got the bank correctly mapped in:
  782. if (iNewBank != iBank)
  783. {
  784. pjDst -= ppdev->cjBank;
  785. iBank = iNewBank;
  786. ppdev->pfnBankMap(ppdev, iBank);
  787. }
  788. }
  789. else
  790. {
  791. // We're done! Turn off banking and leave:
  792. ppdev->pfnBankSelectMode(ppdev, BANK_OFF);
  793. DISPDBG((5, "vPutBits -- exit"));
  794. return;
  795. }
  796. }
  797. }
  798. /******************************Public*Routine******************************\
  799. * VOID vPutBitsLinear
  800. *
  801. * Copies the bits from the given surface to the screen, using the memory
  802. * aperture. Must be pre-clipped.
  803. *
  804. \**************************************************************************/
  805. VOID vPutBitsLinear(
  806. PDEV* ppdev,
  807. SURFOBJ* psoSrc,
  808. RECTL* prclDst, // Absolute coordinates!
  809. POINTL* pptlSrc) // Absolute coordinates!
  810. {
  811. RECTL rclDraw;
  812. LONG cyScan;
  813. LONG lDstDelta;
  814. LONG lSrcDelta;
  815. BYTE* pjDst;
  816. BYTE* pjSrc;
  817. LONG cjScan;
  818. BYTE* pjPorts = ppdev->pjPorts;
  819. DISPDBG((5, "vPutBitsLinear -- enter"));
  820. rclDraw = *prclDst;
  821. ASSERTDD((rclDraw.left >= 0) &&
  822. (rclDraw.top >= 0) &&
  823. (rclDraw.right <= ppdev->cxMemory) &&
  824. (rclDraw.bottom <= ppdev->cyMemory),
  825. "vPutBitsLinear: rectangle wasn't fully clipped");
  826. // Calculate the pointer to the upper-left corner of both rectangles:
  827. lDstDelta = ppdev->lDelta;
  828. pjDst = ppdev->pjScreen + rclDraw.top * lDstDelta
  829. + PELS_TO_BYTES(rclDraw.left);
  830. lSrcDelta = psoSrc->lDelta;
  831. pjSrc = (BYTE*) psoSrc->pvScan0 + (pptlSrc->y * lSrcDelta)
  832. + PELS_TO_BYTES(pptlSrc->x);
  833. cjScan = PELS_TO_BYTES(rclDraw.right - rclDraw.left);
  834. cyScan = (rclDraw.bottom - rclDraw.top);
  835. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  836. vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
  837. TRUE); // Screen is the dest
  838. DISPDBG((5, "vPutBitsLinear -- exit"));
  839. }
  840. /******************************Public*Routine******************************\
  841. * VOID vGetBits
  842. *
  843. * Copies the bits to the given surface from the screen, using the memory
  844. * aperture. Must be pre-clipped.
  845. *
  846. \**************************************************************************/
  847. VOID vGetBits(
  848. PDEV* ppdev,
  849. SURFOBJ* psoDst,
  850. RECTL* prclDst, // Absolute coordinates!
  851. POINTL* pptlSrc) // Absolute coordinates!
  852. {
  853. RECTL rclDraw;
  854. RECTL rclBank;
  855. LONG iBank;
  856. LONG cjOffset;
  857. LONG cyScan;
  858. LONG lDstDelta;
  859. LONG lSrcDelta;
  860. BYTE* pjDst;
  861. BYTE* pjSrc;
  862. LONG cjScan;
  863. LONG iNewBank;
  864. LONG cjRemainder;
  865. BYTE* pjPorts = ppdev->pjPorts;
  866. DISPDBG((5, "vGetBits -- enter"));
  867. rclDraw.left = pptlSrc->x;
  868. rclDraw.top = pptlSrc->y;
  869. rclDraw.right = rclDraw.left + (prclDst->right - prclDst->left);
  870. rclDraw.bottom = rclDraw.top + (prclDst->bottom - prclDst->top);
  871. ASSERTDD((rclDraw.left >= 0) &&
  872. (rclDraw.top >= 0) &&
  873. (rclDraw.right <= ppdev->cxMemory) &&
  874. (rclDraw.bottom <= ppdev->cyMemory),
  875. "Rectangle wasn't fully clipped");
  876. // Compute the first bank, enable banking, then map in iBank.
  877. ppdev->pfnBankCompute(ppdev, &rclDraw, &rclBank, &cjOffset, &iBank);
  878. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  879. ppdev->pfnBankMap(ppdev, iBank);
  880. // Calculate the pointer to the upper-left corner of both rectangles:
  881. lSrcDelta = ppdev->lDelta;
  882. pjSrc = ppdev->pjScreen + rclDraw.top * lSrcDelta
  883. + PELS_TO_BYTES(rclDraw.left)
  884. - cjOffset;
  885. lDstDelta = psoDst->lDelta;
  886. pjDst = (BYTE*) psoDst->pvScan0 + prclDst->top * lDstDelta
  887. + PELS_TO_BYTES(prclDst->left);
  888. while (TRUE)
  889. {
  890. cjScan = PELS_TO_BYTES(rclBank.right - rclBank.left);
  891. cyScan = (rclBank.bottom - rclBank.top);
  892. vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
  893. FALSE); // Screen is the source
  894. if (rclDraw.right != rclBank.right)
  895. {
  896. // Handle the second part of the broken raster:
  897. iBank++;
  898. ppdev->pfnBankMap(ppdev, iBank);
  899. // Number of bytes we've yet to do on the broken scan:
  900. cjRemainder = PELS_TO_BYTES(rclDraw.right - rclBank.right);
  901. // Account for the fact that we're now one bank lower in the
  902. // source:
  903. pjSrc -= ppdev->cjBank;
  904. // Implicitly back up the source and destination pointers to the
  905. // unfinished portion of the scan. Note that we don't have to
  906. // advance the pointers because they're already pointing to the
  907. // beginning of the next scan:
  908. if (DIRECT_ACCESS(ppdev))
  909. {
  910. memcpy(pjDst + (cjScan - lDstDelta),
  911. pjSrc + (cjScan - lSrcDelta),
  912. cjRemainder);
  913. }
  914. else
  915. {
  916. BYTE* pjTmpDst = pjDst + (cjScan - lDstDelta);
  917. BYTE* pjTmpSrc = pjSrc + (cjScan - lSrcDelta);
  918. vAlignedCopy(ppdev, &pjTmpDst, 0, &pjTmpSrc, 0, cjRemainder, 1,
  919. FALSE); // Screen is the source
  920. }
  921. }
  922. if (rclDraw.bottom > rclBank.bottom)
  923. {
  924. rclDraw.top = rclBank.bottom;
  925. ppdev->pfnBankCompute(ppdev, &rclDraw, &rclBank, &cjOffset,
  926. &iNewBank);
  927. // If we just handled the second part of a broken raster,
  928. // then we've already got the bank correctly mapped in:
  929. if (iNewBank != iBank)
  930. {
  931. pjSrc -= ppdev->cjBank;
  932. iBank = iNewBank;
  933. ppdev->pfnBankMap(ppdev, iBank);
  934. }
  935. }
  936. else
  937. {
  938. // We're done! Turn off banking and leave:
  939. ppdev->pfnBankSelectMode(ppdev, BANK_OFF);
  940. DISPDBG((5, "vGetBits -- exit"));
  941. return;
  942. }
  943. }
  944. }
  945. /******************************Public*Routine******************************\
  946. * VOID vGetBitsLinear
  947. *
  948. * Copies the bits to the given surface from the screen, using the memory
  949. * aperture. Must be pre-clipped.
  950. *
  951. \**************************************************************************/
  952. VOID vGetBitsLinear(
  953. PDEV* ppdev,
  954. SURFOBJ* psoDst,
  955. RECTL* prclDst, // Absolute coordinates!
  956. POINTL* pptlSrc) // Absolute coordinates!
  957. {
  958. RECTL rclDraw;
  959. LONG cyScan;
  960. LONG lDstDelta;
  961. LONG lSrcDelta;
  962. BYTE* pjDst;
  963. BYTE* pjSrc;
  964. LONG cjScan;
  965. BYTE* pjPorts = ppdev->pjPorts;
  966. DISPDBG((5, "vGetBitsLinear -- enter"));
  967. rclDraw.left = pptlSrc->x;
  968. rclDraw.top = pptlSrc->y;
  969. rclDraw.right = rclDraw.left + (prclDst->right - prclDst->left);
  970. rclDraw.bottom = rclDraw.top + (prclDst->bottom - prclDst->top);
  971. ASSERTDD((rclDraw.left >= 0) &&
  972. (rclDraw.top >= 0) &&
  973. (rclDraw.right <= ppdev->cxMemory) &&
  974. (rclDraw.bottom <= ppdev->cyMemory),
  975. "vGetBitsLinear: rectangle wasn't fully clipped");
  976. // Calculate the pointer to the upper-left corner of both rectangles:
  977. lSrcDelta = ppdev->lDelta;
  978. pjSrc = ppdev->pjScreen + rclDraw.top * lSrcDelta
  979. + PELS_TO_BYTES(rclDraw.left);
  980. lDstDelta = psoDst->lDelta;
  981. pjDst = (BYTE*) psoDst->pvScan0 + prclDst->top * lDstDelta
  982. + PELS_TO_BYTES(prclDst->left);
  983. cjScan = PELS_TO_BYTES(rclDraw.right - rclDraw.left);
  984. cyScan = (rclDraw.bottom - rclDraw.top);
  985. ppdev->pfnBankSelectMode(ppdev, BANK_ON);
  986. vAlignedCopy(ppdev, &pjDst, lDstDelta, &pjSrc, lSrcDelta, cjScan, cyScan,
  987. FALSE); // Screen is the source
  988. DISPDBG((5, "vGetBitsLinear -- exit"));
  989. }