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.

1146 lines
36 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: ddraw64.c
  3. *
  4. * Implements all the DirectDraw components for the MACH 64 driver.
  5. *
  6. * Copyright (c) 1995-1996 Microsoft Corporation
  7. \**************************************************************************/
  8. #include "precomp.h"
  9. /******************************Public*Routine******************************\
  10. * VOID vGetDisplayDuration64
  11. *
  12. * Get the length, in EngQueryPerformanceCounter() ticks, of a refresh cycle.
  13. *
  14. * If we could trust the miniport to return back and accurate value for
  15. * the refresh rate, we could use that. Unfortunately, our miniport doesn't
  16. * ensure that it's an accurate value.
  17. *
  18. \**************************************************************************/
  19. #define NUM_VBLANKS_TO_MEASURE 1
  20. #define NUM_MEASUREMENTS_TO_TAKE 8
  21. void DeskScanCallback (PDEV* );
  22. VOID vGetDisplayDuration64(PDEV* ppdev)
  23. {
  24. BYTE* pjMmBase;
  25. LONG i;
  26. LONG j;
  27. LONGLONG li;
  28. LONGLONG liMin;
  29. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  30. pjMmBase = ppdev->pjMmBase;
  31. memset(&ppdev->flipRecord, 0, sizeof(ppdev->flipRecord));
  32. // Warm up EngQUeryPerformanceCounter to make sure it's in the working
  33. // set:
  34. EngQueryPerformanceCounter(&li);
  35. // Sometimes the IN_VBLANK_STATUS will always return TRUE. In this case,
  36. // we don't want to do the normal stuff here. Instead, we will just
  37. // say that the flip duration is always 60Hz which should be the worst
  38. // case scenario.
  39. if (ppdev->bPassVBlank == FALSE)
  40. {
  41. LONGLONG liRate;
  42. EngQueryPerformanceFrequency(&liRate);
  43. liRate *= 167000;
  44. ppdev->flipRecord.liFlipDuration = liRate / 10000000;
  45. ppdev->flipRecord.liFlipTime = li;
  46. ppdev->flipRecord.bFlipFlag = FALSE;
  47. ppdev->flipRecord.fpFlipFrom = 0;
  48. return;
  49. }
  50. // Unfortunately, since NT is a proper multitasking system, we can't
  51. // just disable interrupts to take an accurate reading. We also can't
  52. // do anything so goofy as dynamically change our thread's priority to
  53. // real-time.
  54. //
  55. // So we just do a bunch of short measurements and take the minimum.
  56. //
  57. // It would be 'okay' if we got a result that's longer than the actual
  58. // VBlank cycle time -- nothing bad would happen except that the app
  59. // would run a little slower. We don't want to get a result that's
  60. // shorter than the actual VBlank cycle time -- that could cause us
  61. // to start drawing over a frame before the Flip has occured.
  62. while (IN_VBLANK_64( pjMmBase))
  63. ;
  64. while (!(IN_VBLANK_64( pjMmBase)))
  65. ;
  66. for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++)
  67. {
  68. // We're at the start of the VBlank active cycle!
  69. EngQueryPerformanceCounter(&aliMeasurement[i]);
  70. // Okay, so life in a multi-tasking environment isn't all that
  71. // simple. What if we had taken a context switch just before
  72. // the above EngQueryPerformanceCounter call, and now were half
  73. // way through the VBlank inactive cycle? Then we would measure
  74. // only half a VBlank cycle, which is obviously bad. The worst
  75. // thing we can do is get a time shorter than the actual VBlank
  76. // cycle time.
  77. //
  78. // So we solve this by making sure we're in the VBlank active
  79. // time before and after we query the time. If it's not, we'll
  80. // sync up to the next VBlank (it's okay to measure this period --
  81. // it will be guaranteed to be longer than the VBlank cycle and
  82. // will likely be thrown out when we select the minimum sample).
  83. // There's a chance that we'll take a context switch and return
  84. // just before the end of the active VBlank time -- meaning that
  85. // the actual measured time would be less than the true amount --
  86. // but since the VBlank is active less than 1% of the time, this
  87. // means that we would have a maximum of 1% error approximately
  88. // 1% of the times we take a context switch. An acceptable risk.
  89. //
  90. // This next line will cause us wait if we're no longer in the
  91. // VBlank active cycle as we should be at this point:
  92. while (!(IN_VBLANK_64( pjMmBase)))
  93. ;
  94. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  95. {
  96. while (IN_VBLANK_64( pjMmBase))
  97. ;
  98. while (!(IN_VBLANK_64( pjMmBase)))
  99. ;
  100. }
  101. }
  102. EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
  103. // Use the minimum, ignoring the POTENTIALLY BOGUS FIRST
  104. liMin = aliMeasurement[2] - aliMeasurement[1];
  105. DISPDBG((10, "Refresh count: %li - %li", 1, (ULONG) liMin));
  106. for (i = 3; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
  107. {
  108. li = aliMeasurement[i] - aliMeasurement[i - 1];
  109. DISPDBG((10, " %li - %li", i, (ULONG) li));
  110. if (li < liMin)
  111. liMin = li;
  112. }
  113. // Round the result:
  114. ppdev->flipRecord.liFlipDuration
  115. = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
  116. DISPDBG((10, "Frequency %li.%03li Hz",
  117. (ULONG) (EngQueryPerformanceFrequency(&li),
  118. li / ppdev->flipRecord.liFlipDuration),
  119. (ULONG) (EngQueryPerformanceFrequency(&li),
  120. ((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
  121. ppdev->flipRecord.liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE];
  122. ppdev->flipRecord.bFlipFlag = FALSE;
  123. ppdev->flipRecord.fpFlipFrom = 0;
  124. }
  125. /******************************Public*Routine******************************\
  126. * HRESULT vUpdateFlipStatus
  127. *
  128. * Checks and sees if the most recent flip has occurred.
  129. *
  130. \**************************************************************************/
  131. static HRESULT vUpdateFlipStatus(
  132. PDEV* ppdev,
  133. FLATPTR fpVidMem)
  134. {
  135. BYTE* pjMmBase;
  136. LONGLONG liTime;
  137. pjMmBase = ppdev->pjMmBase;
  138. if ((ppdev->flipRecord.bFlipFlag) &&
  139. ((fpVidMem == 0) || (fpVidMem == ppdev->flipRecord.fpFlipFrom)))
  140. {
  141. if (ppdev->bPassVBlank)
  142. {
  143. if (IN_VBLANK_64( pjMmBase))
  144. {
  145. if (ppdev->flipRecord.bWasEverInDisplay)
  146. {
  147. ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE;
  148. }
  149. }
  150. else //if (IN_DISPLAY(pjMmBase))
  151. {
  152. if( ppdev->flipRecord.bHaveEverCrossedVBlank )
  153. {
  154. ppdev->flipRecord.bFlipFlag = FALSE;
  155. return(DD_OK);
  156. }
  157. ppdev->flipRecord.bWasEverInDisplay = TRUE;
  158. // If the current scan line is <= the scan line at flip
  159. // time then we KNOW that the flip occurred!
  160. if ( CURRENT_VLINE_64(pjMmBase) < ppdev->flipRecord.wFlipScanLine)
  161. {
  162. ppdev->flipRecord.bFlipFlag = FALSE;
  163. return(DD_OK);
  164. }
  165. }
  166. }
  167. EngQueryPerformanceCounter(&liTime);
  168. if (liTime - ppdev->flipRecord.liFlipTime
  169. <= ppdev->flipRecord.liFlipDuration)
  170. {
  171. return(DDERR_WASSTILLDRAWING);
  172. }
  173. ppdev->flipRecord.bFlipFlag = FALSE;
  174. }
  175. return(DD_OK);
  176. }
  177. /******************************Public*Routine******************************\
  178. * DWORD DdBlt64
  179. *
  180. \**************************************************************************/
  181. DWORD DdBlt64(
  182. PDD_BLTDATA lpBlt)
  183. {
  184. DWORD scLeftRight;
  185. DWORD scTopBottom;
  186. DWORD dpPixWidth;
  187. DWORD dpMix;
  188. DWORD guiCntl;
  189. DWORD srcOffPitch;
  190. DWORD srcYX;
  191. DWORD dstOffPitch;
  192. DWORD dstYX;
  193. DWORD RGBBitCount;
  194. LONG lPitch;
  195. ULONG dstOffPitchSave;
  196. DWORD srcWidth, srcHeight;
  197. DWORD dstWidth, dstHeight;
  198. DWORD srcOffset, dstOffset;
  199. DWORD frgdClr;
  200. RECTL rSrc;
  201. RECTL rDest;
  202. DWORD dwFlags;
  203. PDEV* ppdev;
  204. BYTE* pjMmBase;
  205. BYTE rop;
  206. HRESULT ddrval;
  207. PDD_SURFACE_LOCAL psrcsurfx;
  208. PDD_SURFACE_LOCAL pdestsurfx;
  209. PDD_SURFACE_GLOBAL psrcsurf;
  210. PDD_SURFACE_GLOBAL pdestsurf;
  211. ppdev = (PDEV*) lpBlt->lpDD->dhpdev;
  212. pjMmBase = ppdev->pjMmBase;
  213. pdestsurfx = lpBlt->lpDDDestSurface;
  214. pdestsurf = pdestsurfx->lpGbl;
  215. /*
  216. * is a flip in progress?
  217. */
  218. ddrval = vUpdateFlipStatus( ppdev, pdestsurf->fpVidMem );
  219. if( ddrval != DD_OK )
  220. {
  221. lpBlt->ddRVal = ddrval;
  222. return DDHAL_DRIVER_HANDLED;
  223. }
  224. dwFlags = lpBlt->dwFlags;
  225. /*
  226. * If async, then only work if bltter isn't busy
  227. * This should probably be a little more specific to each call, but
  228. * waiting for 16 is pretty close
  229. */
  230. if( dwFlags & DDBLT_ASYNC )
  231. {
  232. if( M64_FIFO_SPACE_AVAIL( ppdev, pjMmBase, 16 ) )
  233. {
  234. lpBlt->ddRVal = DDERR_WASSTILLDRAWING;
  235. return DDHAL_DRIVER_HANDLED;
  236. }
  237. }
  238. /*
  239. * copy src/dest rects
  240. */
  241. rSrc = lpBlt->rSrc;
  242. rDest = lpBlt->rDest;
  243. /*
  244. * get offset, width, and height for source
  245. */
  246. rop = (BYTE) (lpBlt->bltFX.dwROP >> 16);
  247. psrcsurfx = lpBlt->lpDDSrcSurface;
  248. if( psrcsurfx != NULL )
  249. {
  250. psrcsurf = psrcsurfx->lpGbl;
  251. srcOffset = (DWORD)(psrcsurf->fpVidMem);
  252. srcWidth = rSrc.right - rSrc.left;
  253. srcHeight = rSrc.bottom - rSrc.top;
  254. RGBBitCount = ppdev->cjPelSize * 8;
  255. lPitch = psrcsurf->lPitch;
  256. }
  257. else
  258. {
  259. psrcsurf = NULL;
  260. }
  261. /*
  262. * setup dwSRC_LEFT_RIGHT, dwSRC_TOP_BOTTOM, and srcOffPitch
  263. */
  264. switch ( RGBBitCount )
  265. {
  266. case 8:
  267. srcOffPitch = (srcOffset >> 3) |
  268. ((lPitch >> 3) << SHIFT_DST_PITCH);
  269. break;
  270. case 16:
  271. srcOffPitch = (srcOffset >> 3) |
  272. ((lPitch >> 4) << SHIFT_DST_PITCH);
  273. break;
  274. case 24:
  275. srcOffPitch = (srcOffset >> 3 ) |
  276. ((lPitch >> 3) << SHIFT_DST_PITCH);
  277. rSrc.left = rSrc.left * MUL24;
  278. rSrc.right = rSrc.right * MUL24;
  279. srcWidth = srcWidth * MUL24;
  280. break;
  281. }
  282. scTopBottom = ( DWORD )( ppdev->cyScreen - 1 ) << SHIFT_SC_BOTTOM;
  283. /*
  284. * get offset, width, and height for destination
  285. */
  286. dstOffset = (DWORD)(pdestsurf->fpVidMem);
  287. dstWidth = rDest.right - rDest.left;
  288. dstHeight = rDest.bottom - rDest.top;
  289. /*
  290. * get bpp and pitch for destination
  291. */
  292. RGBBitCount = ppdev->cjPelSize * 8;
  293. lPitch = pdestsurf->lPitch;
  294. /*
  295. * setup dstOffPitch, and dpPixWidth
  296. */
  297. switch ( RGBBitCount )
  298. {
  299. case 8:
  300. scLeftRight = (DWORD)(ppdev->cxScreen- 1) << SHIFT_SC_RIGHT;
  301. dstOffPitch = (dstOffset >> 3) |
  302. ((lPitch >> 3) << SHIFT_DST_PITCH);
  303. dpPixWidth = DP_PIX_WIDTH_8BPP;
  304. break;
  305. case 16:
  306. scLeftRight = (DWORD)(ppdev->cxScreen- 1) << SHIFT_SC_RIGHT;
  307. dstOffPitch = (dstOffset >> 3) |
  308. ((lPitch >> 4) << SHIFT_DST_PITCH);
  309. dpPixWidth = DP_PIX_WIDTH_15BPP;
  310. break;
  311. case 24:
  312. scLeftRight = (DWORD)(ppdev->cxScreen* MUL24 - 1) << SHIFT_SC_RIGHT;
  313. dstOffPitch = (dstOffset >> 3) |
  314. ((lPitch >> 3) << SHIFT_DST_PITCH);
  315. dpPixWidth = DP_PIX_WIDTH_24BPP;
  316. rDest.left = rDest.left * MUL24;
  317. rDest.right = rDest.right * MUL24;
  318. dstWidth = dstWidth * MUL24;
  319. break;
  320. }
  321. /*
  322. * setup guiCntl, srcYX and dstYX
  323. */
  324. guiCntl = DST_X_DIR | DST_Y_DIR; // unbounded Y, left-to-right, top-to-bottom
  325. srcYX = rSrc.top | (rSrc.left << SHIFT_SRC_X);
  326. dstYX = rDest.top | (rDest.left << SHIFT_DST_X);
  327. /*
  328. * check if source and destination of blit are on the same surface; if
  329. * so, we may have to reverse the direction of blit
  330. */
  331. if( psrcsurf == pdestsurf )
  332. {
  333. if( rDest.top >= rSrc.top )
  334. {
  335. guiCntl &= ~DST_Y_DIR;
  336. srcYX = ( srcYX & 0xFFFF0000 ) | (rSrc.bottom-1);
  337. dstYX = ( dstYX & 0xFFFF0000 ) | (rDest.bottom-1);
  338. }
  339. if( rDest.left >= rSrc.left )
  340. {
  341. guiCntl &= ~DST_X_DIR;
  342. srcYX = (srcYX & 0x0000FFFF) | ((rSrc.right-1) << SHIFT_SRC_X);
  343. dstYX = (dstYX & 0x0000FFFF) | ((rDest.right-1) << SHIFT_DST_X);
  344. }
  345. }
  346. //
  347. // ROP blts
  348. //
  349. // NT only currently support SRCCOPY ROPS, so assume
  350. // that any ROP is SRCCOPY
  351. //
  352. if( dwFlags & DDBLT_ROP )
  353. {
  354. dpMix = ( DP_MIX_S & DP_FRGD_MIX ) | ( DP_MIX_D & DP_BKGD_MIX );
  355. DISPDBG((10,"SRCCOPY...."));
  356. //
  357. // set up the blt
  358. //
  359. M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 9);
  360. M64_OD( pjMmBase, DP_WRITE_MASK, 0xFFFFFFFF );
  361. M64_OD( pjMmBase, DP_PIX_WIDTH, dpPixWidth );
  362. M64_OD( pjMmBase, SC_LEFT_RIGHT, scLeftRight );
  363. M64_OD( pjMmBase, SC_TOP_BOTTOM, scTopBottom );
  364. M64_OD( pjMmBase, SRC_OFF_PITCH, srcOffPitch );
  365. M64_OD( pjMmBase, DST_OFF_PITCH, dstOffPitch );
  366. M64_OD( pjMmBase, SRC_HEIGHT1_WIDTH1,
  367. srcHeight | ( srcWidth << SHIFT_SRC_WIDTH1 ) );
  368. M64_OD( pjMmBase, DP_SRC, DP_FRGD_SRC & DP_SRC_VRAM );
  369. M64_OD( pjMmBase, DP_MIX, dpMix );
  370. if( dwFlags & (DDBLT_KEYSRCOVERRIDE|DDBLT_KEYDESTOVERRIDE) )
  371. {
  372. M64_CHECK_FIFO_SPACE( ppdev, pjMmBase, 7 );
  373. if ( dwFlags & DDBLT_KEYSRCOVERRIDE )
  374. {
  375. M64_OD( pjMmBase, CLR_CMP_CNTL, CLR_CMP_SRC | CLR_CMP_FCN_EQ );
  376. M64_OD( pjMmBase, CLR_CMP_MSK, 0xFFFFFFFF ); // enable all bit planes for comparision
  377. M64_OD( pjMmBase, CLR_CMP_CLR,
  378. lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceLowValue );
  379. }
  380. else
  381. {
  382. M64_OD( pjMmBase, CLR_CMP_CNTL, CLR_CMP_FCN_NE );
  383. M64_OD( pjMmBase, CLR_CMP_MSK, 0xFFFFFFFF ); // enable all bit planes for comparision
  384. M64_OD( pjMmBase, CLR_CMP_CLR,
  385. lpBlt->bltFX.ddckDestColorkey.dwColorSpaceLowValue );
  386. }
  387. }
  388. else
  389. {
  390. M64_CHECK_FIFO_SPACE( ppdev, pjMmBase, 5 );
  391. M64_OD( pjMmBase, CLR_CMP_CNTL, 0x00000000 ); // disable color key
  392. DISPDBG((10,"wr CLR_CMP_CNTL %x (DISABLE)",0));
  393. }
  394. M64_OD( pjMmBase, GUI_TRAJ_CNTL, guiCntl );
  395. M64_OD( pjMmBase, SRC_Y_X, srcYX );
  396. M64_OD( pjMmBase, DST_Y_X, dstYX );
  397. /*
  398. * DST_HEIGHT_WIDTH is an initiator, this actually starts the blit
  399. */
  400. M64_OD( pjMmBase, DST_HEIGHT_WIDTH, dstHeight | (dstWidth << SHIFT_DST_WIDTH) );
  401. }
  402. /*
  403. * color fill
  404. */
  405. else if( dwFlags & DDBLT_COLORFILL )
  406. {
  407. M64_CHECK_FIFO_SPACE ( ppdev,pjMmBase, 12 );
  408. M64_OD( pjMmBase, DP_WRITE_MASK, 0xFFFFFFFF );
  409. M64_OD( pjMmBase, DP_PIX_WIDTH, dpPixWidth );
  410. M64_OD( pjMmBase, CLR_CMP_CNTL, 0x00000000 ); /* disable */
  411. M64_OD( pjMmBase, SC_LEFT_RIGHT, scLeftRight );
  412. M64_OD( pjMmBase, SC_TOP_BOTTOM, scTopBottom );
  413. M64_OD( pjMmBase, DST_OFF_PITCH, dstOffPitch );
  414. M64_OD( pjMmBase, DP_SRC, DP_FRGD_SRC & DP_SRC_FRGD );
  415. M64_OD( pjMmBase, DP_MIX, (DP_MIX_S & DP_FRGD_MIX) | /* frgd:paint, */
  416. (DP_MIX_D & DP_BKGD_MIX) ); /* bkgd:leave_alone */
  417. M64_OD( pjMmBase, DP_FRGD_CLR, lpBlt->bltFX.dwFillColor );
  418. M64_OD( pjMmBase, GUI_TRAJ_CNTL, guiCntl );
  419. M64_OD( pjMmBase, DST_Y_X, dstYX );
  420. /* DST_HEIGHT_WIDTH is an initiator, this actually starts the blit */
  421. M64_OD( pjMmBase, DST_HEIGHT_WIDTH,
  422. dstHeight | ( dstWidth << SHIFT_DST_WIDTH ) );
  423. }
  424. /*
  425. * don't handle
  426. */
  427. else
  428. {
  429. return DDHAL_DRIVER_NOTHANDLED;
  430. }
  431. // Don't forget to reset the clip register and the default pixel width:
  432. // The rest of the driver code assumes that this is set by default!
  433. M64_CHECK_FIFO_SPACE ( ppdev, pjMmBase, 8);
  434. M64_OD(pjMmBase, DST_OFF_PITCH, ppdev->ulScreenOffsetAndPitch );
  435. M64_OD(pjMmBase, SRC_OFF_PITCH, ppdev->ulScreenOffsetAndPitch );
  436. M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth);
  437. M64_OD(pjMmBase, SC_LEFT_RIGHT, PACKPAIR(0, M64_MAX_SCISSOR_R));
  438. M64_OD(pjMmBase, SC_TOP_BOTTOM, PACKPAIR(0, M64_MAX_SCISSOR_B));
  439. M64_OD( pjMmBase, CLR_CMP_CNTL, 0x00000000 ); /* disable */
  440. M64_OD( pjMmBase, GUI_TRAJ_CNTL, DST_X_DIR | DST_Y_DIR );
  441. lpBlt->ddRVal = DD_OK;
  442. return DDHAL_DRIVER_HANDLED;
  443. }
  444. /******************************Public*Routine******************************\
  445. * DWORD DdFlip64
  446. *
  447. \**************************************************************************/
  448. DWORD DdFlip64(
  449. PDD_FLIPDATA lpFlip)
  450. {
  451. PDEV* ppdev;
  452. BYTE* pjMmBase;
  453. HRESULT ddrval;
  454. ULONG ulMemoryOffset;
  455. ULONG uVal;
  456. static ULONG flipcnt = 0;
  457. DISPDBG((10, "Enter DDFlip64"));
  458. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  459. pjMmBase = ppdev->pjMmBase;
  460. flipcnt++;
  461. // Is the current flip still in progress?
  462. //
  463. // Don't want a flip to work until after the last flip is done,
  464. // so we ask for the general flip status and ignore the vmem.
  465. ddrval = vUpdateFlipStatus(ppdev, 0);
  466. if ((ddrval != DD_OK) || (DRAW_ENGINE_BUSY_64( ppdev,pjMmBase)))
  467. {
  468. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  469. return(DDHAL_DRIVER_HANDLED);
  470. }
  471. // code for overlay support
  472. /*
  473. * Do we have a flipping overlay surface
  474. */
  475. if ( lpFlip->lpSurfTarg->ddsCaps.dwCaps & DDSCAPS_OVERLAY )
  476. {
  477. ppdev->OverlayInfo16.dwFlags |= UPDATEOVERLAY;
  478. ppdev->OverlayInfo16.dwBuf0Start =
  479. (DWORD)(lpFlip->lpSurfTarg->lpGbl->fpVidMem);
  480. ppdev->OverlayInfo16.dwBuf1Start =
  481. (DWORD)(lpFlip->lpSurfTarg->lpGbl->fpVidMem);
  482. DeskScanCallback (ppdev );
  483. ppdev->OverlayInfo16.dwFlags &= ~UPDATEOVERLAY;
  484. if (ppdev->bPassVBlank)
  485. {
  486. while (IN_VBLANK_64(pjMmBase))
  487. ;
  488. }
  489. lpFlip->ddRVal = DD_OK;
  490. return DDHAL_DRIVER_HANDLED;
  491. }
  492. // end code for overlay support
  493. ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem);
  494. uVal = M64_ID( pjMmBase, CRTC_OFF_PITCH );
  495. uVal &= 0xFFC00000;
  496. uVal |= (ulMemoryOffset >> 3);
  497. // Make sure that the border/blanking period isn't active; wait if
  498. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  499. // that will increase the odds that we can't flip the next time:
  500. if (ppdev->bPassVBlank)
  501. {
  502. while (IN_VBLANK_64(pjMmBase))
  503. ;
  504. }
  505. // Do the flip
  506. M64_OD_DIRECT(pjMmBase, CRTC_OFF_PITCH, uVal );
  507. // Remember where and when we were when we did the flip:
  508. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  509. ppdev->flipRecord.bFlipFlag = TRUE;
  510. ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
  511. ppdev->flipRecord.bWasEverInDisplay = FALSE;
  512. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  513. if( IN_VBLANK_64( pjMmBase) && ppdev->bPassVBlank )
  514. {
  515. ppdev->flipRecord.wFlipScanLine = 0;
  516. }
  517. else
  518. {
  519. ppdev->flipRecord.wFlipScanLine = CURRENT_VLINE_64(pjMmBase);
  520. // if we have a context switch and we are returning in the middle of a VBlank, the current line will be invalid
  521. if( (ULONG)ppdev->flipRecord.wFlipScanLine > (ULONG)ppdev->cyScreen)
  522. {
  523. ppdev->flipRecord.wFlipScanLine = 0;
  524. }
  525. }
  526. lpFlip->ddRVal = DD_OK;
  527. DISPDBG((10, "Exit DDFlip64"));
  528. return(DDHAL_DRIVER_HANDLED);
  529. }
  530. /******************************Public*Routine******************************\
  531. * DWORD DdLock
  532. *
  533. \**************************************************************************/
  534. DWORD DdLock64(
  535. PDD_LOCKDATA lpLock)
  536. {
  537. PDEV* ppdev;
  538. HRESULT ddrval;
  539. ppdev = (PDEV*) lpLock->lpDD->dhpdev;
  540. // Check to see if any pending physical flip has occurred.
  541. // Don't allow a lock if a blt is in progress:
  542. ddrval = vUpdateFlipStatus(ppdev, lpLock->lpDDSurface->lpGbl->fpVidMem);
  543. if (ddrval != DD_OK)
  544. {
  545. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  546. return(DDHAL_DRIVER_HANDLED);
  547. }
  548. // Here's one of the places where the Windows 95 and Windows NT DirectDraw
  549. // implementations differ: on Windows NT, you should watch for
  550. // DDLOCK_WAIT and loop in the driver while the accelerator is busy.
  551. // On Windows 95, it doesn't really matter.
  552. //
  553. // (The reason is that Windows NT allows applications to draw directly
  554. // to the frame buffer even while the accelerator is running, and does
  555. // not synchronize everything on the Win16Lock. Note that on Windows NT,
  556. // it is even possible for multiple threads to be holding different
  557. // DirectDraw surface locks at the same time.)
  558. if (lpLock->dwFlags & DDLOCK_WAIT)
  559. {
  560. do {} while (DRAW_ENGINE_BUSY_64(ppdev, ppdev->pjMmBase));
  561. }
  562. else if (DRAW_ENGINE_BUSY_64(ppdev, ppdev->pjMmBase))
  563. {
  564. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  565. return(DDHAL_DRIVER_HANDLED);
  566. }
  567. return(DDHAL_DRIVER_NOTHANDLED);
  568. }
  569. /******************************Public*Routine******************************\
  570. * DWORD DdGetBltStatus64
  571. *
  572. * Doesn't currently really care what surface is specified, just checks
  573. * and goes.
  574. *
  575. \**************************************************************************/
  576. DWORD DdGetBltStatus64(
  577. PDD_GETBLTSTATUSDATA lpGetBltStatus)
  578. {
  579. PDEV* ppdev;
  580. HRESULT ddRVal;
  581. ppdev = (PDEV*) lpGetBltStatus->lpDD->dhpdev;
  582. ddRVal = DD_OK;
  583. if (lpGetBltStatus->dwFlags == DDGBS_CANBLT)
  584. {
  585. // DDGBS_CANBLT case: can we add a blt?
  586. ddRVal = vUpdateFlipStatus(ppdev,
  587. lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
  588. if (ddRVal == DD_OK)
  589. {
  590. // There was no flip going on, so is there room in the FIFO
  591. // to add a blt?
  592. if (M64_FIFO_SPACE_AVAIL(ppdev,ppdev->pjMmBase,12)) // Should match DdBlt//XXX
  593. {
  594. ddRVal = DDERR_WASSTILLDRAWING;
  595. }
  596. }
  597. }
  598. else
  599. {
  600. // DDGBS_ISBLTDONE case: is a blt in progress?
  601. if (DRAW_ENGINE_BUSY_64( ppdev,ppdev->pjMmBase))
  602. {
  603. ddRVal = DDERR_WASSTILLDRAWING;
  604. }
  605. }
  606. lpGetBltStatus->ddRVal = ddRVal;
  607. return(DDHAL_DRIVER_HANDLED);
  608. }
  609. /******************************Public*Routine******************************\
  610. * DWORD DdMapMemory64
  611. *
  612. * This is a new DDI call specific to Windows NT that is used to map
  613. * or unmap all the application modifiable portions of the frame buffer
  614. * into the specified process's address space.
  615. *
  616. \**************************************************************************/
  617. DWORD DdMapMemory64(
  618. PDD_MAPMEMORYDATA lpMapMemory)
  619. {
  620. PDEV* ppdev;
  621. VIDEO_SHARE_MEMORY ShareMemory;
  622. VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation;
  623. DWORD ReturnedDataLength;
  624. ppdev = (PDEV*) lpMapMemory->lpDD->dhpdev;
  625. if (lpMapMemory->bMap)
  626. {
  627. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  628. // 'RequestedVirtualAddress' isn't actually used for the SHARE IOCTL:
  629. ShareMemory.RequestedVirtualAddress = 0;
  630. // We map in starting at the top of the frame buffer:
  631. ShareMemory.ViewOffset = 0;
  632. // We map down to the end of the frame buffer.
  633. //
  634. // Note: There is a 64k granularity on the mapping (meaning that
  635. // we have to round up to 64k).
  636. //
  637. // Note: If there is any portion of the frame buffer that must
  638. // not be modified by an application, that portion of memory
  639. // MUST NOT be mapped in by this call. This would include
  640. // any data that, if modified by a malicious application,
  641. // would cause the driver to crash. This could include, for
  642. // example, any DSP code that is kept in off-screen memory.
  643. // ** NOTE ** : We must protect the graphics contexts from the user.
  644. // The contexts are located at the high end of graphics memory.
  645. // ppdev->cyMemory is adjusted when the contexts are allocated to
  646. // 'hide' this memory from heap allocation. DDraw init also forces
  647. // the offscreen memory passed to DDraw to end on a 64k boundary
  648. // to fit within the ShareMemory.ViewSize.
  649. //
  650. ShareMemory.ViewSize
  651. = ROUND_DOWN_TO_64K(ppdev->cyMemory * ppdev->lDelta);
  652. if (EngDeviceIoControl(ppdev->hDriver,
  653. IOCTL_VIDEO_SHARE_VIDEO_MEMORY,
  654. &ShareMemory,
  655. sizeof(VIDEO_SHARE_MEMORY),
  656. &ShareMemoryInformation,
  657. sizeof(VIDEO_SHARE_MEMORY_INFORMATION),
  658. &ReturnedDataLength))
  659. {
  660. lpMapMemory->ddRVal = DDERR_GENERIC;
  661. return(DDHAL_DRIVER_HANDLED);
  662. }
  663. lpMapMemory->fpProcess =(FLATPTR)ShareMemoryInformation.VirtualAddress;
  664. }
  665. else
  666. {
  667. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  668. ShareMemory.ViewOffset = 0;
  669. ShareMemory.ViewSize = 0;
  670. ShareMemory.RequestedVirtualAddress = (VOID*) lpMapMemory->fpProcess;
  671. if (EngDeviceIoControl(ppdev->hDriver,
  672. IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY,
  673. &ShareMemory,
  674. sizeof(VIDEO_SHARE_MEMORY),
  675. NULL,
  676. 0,
  677. &ReturnedDataLength))
  678. {
  679. RIP("Failed IOCTL_VIDEO_UNSHARE_MEMORY");
  680. }
  681. }
  682. lpMapMemory->ddRVal = DD_OK;
  683. return(DDHAL_DRIVER_HANDLED);
  684. }
  685. /******************************Public*Routine******************************\
  686. * DWORD DdGetFlipStatus64
  687. *
  688. * If the display has gone through one refresh cycle since the flip
  689. * occurred, we return DD_OK. If it has not gone through one refresh
  690. * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
  691. * is still busy "drawing" the flipped page. We also return
  692. * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted
  693. * to know if they could flip yet.
  694. *
  695. \**************************************************************************/
  696. DWORD DdGetFlipStatus64(
  697. PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  698. {
  699. PDEV* ppdev;
  700. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  701. // We don't want a flip to work until after the last flip is done,
  702. // so we ask for the general flip status and ignore the vmem:
  703. lpGetFlipStatus->ddRVal = vUpdateFlipStatus(ppdev, 0);
  704. // Check if the bltter is busy if someone wants to know if they can
  705. // flip:
  706. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  707. {
  708. if ((lpGetFlipStatus->ddRVal == DD_OK) && (DRAW_ENGINE_BUSY_64( ppdev,ppdev->pjMmBase)))
  709. {
  710. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  711. }
  712. }
  713. return(DDHAL_DRIVER_HANDLED);
  714. }
  715. /******************************Public*Routine******************************\
  716. * DWORD DdWaitForVerticalBlank64
  717. *
  718. \**************************************************************************/
  719. DWORD DdWaitForVerticalBlank64(
  720. PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  721. {
  722. PDEV* ppdev;
  723. BYTE* pjMmBase;
  724. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  725. pjMmBase = ppdev->pjMmBase;
  726. lpWaitForVerticalBlank->ddRVal = DD_OK;
  727. if (ppdev->bPassVBlank == FALSE)
  728. {
  729. lpWaitForVerticalBlank->bIsInVB = FALSE;
  730. return(DDHAL_DRIVER_HANDLED);
  731. }
  732. switch (lpWaitForVerticalBlank->dwFlags)
  733. {
  734. case DDWAITVB_I_TESTVB:
  735. // If TESTVB, it's just a request for the current vertical blank
  736. // status:
  737. if (IN_VBLANK_64( pjMmBase))
  738. lpWaitForVerticalBlank->bIsInVB = TRUE;
  739. else
  740. lpWaitForVerticalBlank->bIsInVB = FALSE;
  741. return(DDHAL_DRIVER_HANDLED);
  742. case DDWAITVB_BLOCKBEGIN:
  743. // If BLOCKBEGIN is requested, we wait until the vertical blank
  744. // is over, and then wait for the display period to end:
  745. while (IN_VBLANK_64( pjMmBase))
  746. ;
  747. while (!IN_VBLANK_64( pjMmBase))
  748. ;
  749. return(DDHAL_DRIVER_HANDLED);
  750. case DDWAITVB_BLOCKEND:
  751. // If BLOCKEND is requested, we wait for the vblank interval to end:
  752. while (!(IN_VBLANK_64( pjMmBase)))
  753. ;
  754. while (IN_VBLANK_64( pjMmBase))
  755. ;
  756. return(DDHAL_DRIVER_HANDLED);
  757. }
  758. return(DDHAL_DRIVER_NOTHANDLED);
  759. }
  760. /******************************Public*Routine******************************\
  761. * DWORD DdGetScanLine64
  762. *
  763. \**************************************************************************/
  764. DWORD DdGetScanLine64(
  765. PDD_GETSCANLINEDATA lpGetScanLine)
  766. {
  767. PDEV* ppdev;
  768. BYTE* pjMmBase;
  769. ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
  770. pjMmBase = ppdev->pjMmBase;
  771. // If a vertical blank is in progress, the scan line is indeterminant.
  772. // If the scan line is indeterminant we return the error code
  773. // DDERR_VERTICALBLANKINPROGRESS. Otherwise, we return the scan line
  774. // and a success code:
  775. if (IN_VBLANK_64(pjMmBase) && ppdev->bPassVBlank)
  776. {
  777. lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS;
  778. }
  779. else
  780. {
  781. lpGetScanLine->dwScanLine = CURRENT_VLINE_64(pjMmBase);
  782. lpGetScanLine->ddRVal = DD_OK;
  783. }
  784. return(DDHAL_DRIVER_HANDLED);
  785. }
  786. /******************************Public*Routine******************************\
  787. * BOOL DrvGetDirectDrawInfo64
  788. *
  789. * Will be called before DrvEnableDirectDraw is called.
  790. *
  791. \**************************************************************************/
  792. BOOL DrvGetDirectDrawInfo64(
  793. DHPDEV dhpdev,
  794. DD_HALINFO* pHalInfo,
  795. DWORD* pdwNumHeaps,
  796. VIDEOMEMORY* pvmList, // Will be NULL on first call
  797. DWORD* pdwNumFourCC,
  798. DWORD* pdwFourCC) // Will be NULL on first call
  799. {
  800. BOOL bCanFlip;
  801. PDEV* ppdev;
  802. LONGLONG li;
  803. OH *poh;
  804. DWORD i;
  805. ppdev = (PDEV*) dhpdev;
  806. DISPDBG((10,"DrvGetDirectDrawInfo64"));
  807. memset( pHalInfo, 0, sizeof(*pHalInfo));
  808. pHalInfo->dwSize = sizeof(*pHalInfo);
  809. if ((ppdev->iBitmapFormat == BMF_24BPP) && (ppdev->cxScreen == 1280) ||
  810. (ppdev->iBitmapFormat == BMF_24BPP) && (ppdev->cxScreen == 1152) ||
  811. (ppdev->iBitmapFormat == BMF_16BPP) && (ppdev->cxScreen == 1600)) {
  812. //
  813. // On some DAC/memory combinations, some modes which require more
  814. // than 2M of memory will have screen tearing at the 2M boundary.
  815. //
  816. // As a workaround, the display driver must start the framebuffer
  817. // at an offset which will put the 2M boundary at the start of a
  818. // scanline.
  819. //
  820. // IOCTL_VIDEO_SHARE_VIDEO_MEMORY is rejected in this case so don't
  821. // allow DDRAW to run with these modes.
  822. //
  823. return FALSE;
  824. }
  825. // Current primary surface attributes:
  826. pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
  827. pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen;
  828. pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
  829. pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta;
  830. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  831. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  832. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cBitsPerPel;
  833. DISPDBG((10,"Init pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount %x",pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount));
  834. if (ppdev->iBitmapFormat == BMF_8BPP)
  835. {
  836. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  837. }
  838. // These masks will be zero at 8bpp:
  839. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed;
  840. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen;
  841. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
  842. // I've disabled DirectDraw accelerations (other than direct frame
  843. // buffer access) at 24bpp and 32bpp because we're close to shipping
  844. // and foxbear has a lot of drawing problems in those modes.
  845. if (ppdev->iBitmapFormat < BMF_24BPP)
  846. {
  847. // Set up the pointer to the first available video memory after
  848. // the primary surface:
  849. bCanFlip = FALSE;
  850. // Free up as much off-screen memory as possible:
  851. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  852. // Now simply reserve the biggest chunks for use by DirectDraw:
  853. poh = ppdev->pohDirectDraw;
  854. if (poh == NULL)
  855. {
  856. LONG linesPer64k;
  857. LONG cyMax;
  858. // We need to force the allocation to end before a 64k boundary.
  859. // The graphic's contexts live at the end fo high memory and we MUST
  860. // protect this from DDraw by not mapping this 64k block into user space.
  861. // So we do not allocate the last 64k of graphics memory for DDraw use.
  862. linesPer64k = 0x10000/ppdev->lDelta;
  863. cyMax = ppdev->heap.cyMax - linesPer64k - 1;
  864. if (cyMax <= 0)
  865. {
  866. // In some modes in some memory configurations -- notably
  867. // 1152x864x256 on a 1MB card -- it's possible that the 64k
  868. // we have to reserve to protect the graphics contexts takes
  869. // up all of off-screen memory and extends into on-screen
  870. // memory. For those modes, we have to disable DirectDraw
  871. // entirely.
  872. return(FALSE);
  873. }
  874. DISPDBG((10," *** Alloc Fix lp64k %d cy.Max %x newallocy %x",linesPer64k,ppdev->heap.cyMax,ppdev->heap.cyMax- linesPer64k-1));
  875. poh = pohAllocate(ppdev,
  876. NULL,
  877. ppdev->heap.cxMax,
  878. cyMax,
  879. FLOH_MAKE_PERMANENT);
  880. ppdev->pohDirectDraw = poh;
  881. }
  882. // this will work as is if using the NT common 2-d heap code.
  883. if (poh != NULL)
  884. {
  885. *pdwNumHeaps = 1;
  886. // Check to see if we can allocate memory to the right of the visible
  887. // surface.
  888. // Fill in the list of off-screen rectangles if we've been asked
  889. // to do so:
  890. if (pvmList != NULL)
  891. {
  892. DISPDBG((10, "DirectDraw gets %li x %li surface at (%li, %li)",
  893. poh->cx, poh->cy, poh->x, poh->y));
  894. pvmList->dwFlags = VIDMEM_ISRECTANGULAR;
  895. pvmList->fpStart = (poh->y * ppdev->lDelta)
  896. + (poh->x * ppdev->cjPelSize);
  897. pvmList->dwWidth = poh->cx * ppdev->cjPelSize;
  898. pvmList->dwHeight = poh->cy;
  899. pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  900. if ((DWORD) ppdev->cyScreen <= pvmList->dwHeight)
  901. {
  902. bCanFlip = TRUE;
  903. }
  904. DISPDBG((10,"CanFlip = %d", bCanFlip));
  905. }
  906. }
  907. // Capabilities supported:
  908. pHalInfo->ddCaps.dwCaps = DDCAPS_BLT
  909. | DDCAPS_COLORKEY
  910. | DDCAPS_BLTCOLORFILL
  911. | DDCAPS_READSCANLINE;
  912. pHalInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT;
  913. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
  914. | DDSCAPS_PRIMARYSURFACE;
  915. if (bCanFlip)
  916. {
  917. pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
  918. }
  919. }
  920. else
  921. {
  922. pHalInfo->ddCaps.dwCaps = DDCAPS_READSCANLINE;
  923. }
  924. // dword alignment must be guaranteed for off-screen surfaces:
  925. pHalInfo->vmiData.dwOffscreenAlign = 8;
  926. DISPDBG((10,"DrvGetDirectDrawInfo64 exit"));
  927. return(TRUE);
  928. }