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.

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