Leaked source code of windows server 2003
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.

508 lines
16 KiB

  1. /***************************************************************************
  2. *
  3. * ******************************************
  4. * * Copyright (c) 1996, Cirrus Logic, Inc. *
  5. * * All Rights Reserved *
  6. * ******************************************
  7. *
  8. * PROJECT: Laguna I (CL-GD546x) -
  9. *
  10. * FILE: ddflip.c
  11. *
  12. * AUTHOR: Benny Ng
  13. *
  14. * DESCRIPTION:
  15. * This module implements the DirectDraw FLIP components
  16. * for the Laguna NT driver.
  17. *
  18. * MODULES:
  19. * vGetDisplayDuration()
  20. * vUpdateFlipStatus()
  21. * DdFlip()
  22. * DdWaitForVerticalBlank()
  23. * DdGetFlipStatus()
  24. *
  25. * REVISION HISTORY:
  26. * 7/12/96 Benny Ng Initial version
  27. *
  28. * $Log: X:/log/laguna/nt35/displays/cl546x/ddflip.c $
  29. *
  30. * Rev 1.10 16 Sep 1997 15:04:06 bennyn
  31. *
  32. * Modified for NT DD overlay
  33. *
  34. * Rev 1.9 29 Aug 1997 17:42:20 RUSSL
  35. * Added 65 overlay support
  36. *
  37. * Rev 1.8 11 Aug 1997 14:07:58 bennyn
  38. *
  39. * Enabled GetScanLine() (for PDR 10254)
  40. *
  41. ****************************************************************************
  42. ****************************************************************************/
  43. /*----------------------------- INCLUDES ----------------------------------*/
  44. #include "precomp.h"
  45. //
  46. // This file isn't used in NT 3.51
  47. //
  48. #ifndef WINNT_VER35
  49. /*----------------------------- DEFINES -----------------------------------*/
  50. //#define DBGBRK
  51. #define DBGLVL 1
  52. #define CSL 0x00C4
  53. #define CSL_5464 0x0140
  54. /*--------------------- STATIC FUNCTION PROTOTYPES ------------------------*/
  55. /*--------------------------- ENUMERATIONS --------------------------------*/
  56. /*----------------------------- TYPEDEFS ----------------------------------*/
  57. /*-------------------------- STATIC VARIABLES -----------------------------*/
  58. /*-------------------------- GLOBAL FUNCTIONS -----------------------------*/
  59. #if DRIVER_5465 && defined(OVERLAY)
  60. // CurrentVLine is in ddinline.h for overlay
  61. #else
  62. /***************************************************************************
  63. *
  64. * FUNCTION: CurrentVLine
  65. *
  66. * DESCRIPTION:
  67. *
  68. ****************************************************************************/
  69. static __inline int CurrentVLine (PDEV* ppdev)
  70. {
  71. WORD cline;
  72. PBYTE pMMReg = (PBYTE) ppdev->pLgREGS_real;
  73. PWORD pCSL;
  74. BYTE tmpb;
  75. // on 5462 there is no CurrentScanLine register
  76. // on RevAA of 5465 it's busted
  77. if ((CL_GD5462 == ppdev->dwLgDevID) ||
  78. ((CL_GD5465 == ppdev->dwLgDevID) && (0 == ppdev->dwLgDevRev)))
  79. return 0;
  80. if (IN_VBLANK)
  81. return 0;
  82. // read current scanline
  83. if (ppdev->dwLgDevID == CL_GD5464)
  84. pCSL = (PWORD) (pMMReg + CSL_5464);
  85. else
  86. pCSL = (PWORD) (pMMReg + CSL);
  87. cline = *pCSL & 0x0FFF;
  88. // if scanline doubling is enabled, divide current scanline by 2
  89. tmpb = (BYTE) LLDR_SZ (grCR9);
  90. if (0x80 & tmpb)
  91. cline /= 2;
  92. // if current scanline is past end of visible screen return 0
  93. if (cline >= ppdev->cyScreen)
  94. return 0;
  95. else
  96. return cline;
  97. }
  98. #endif
  99. /****************************************************************************
  100. * FUNCTION NAME: vGetDisplayDuration
  101. *
  102. * DESCRIPTION: Get the length, in EngQueryPerformanceCounter() ticks,
  103. * of a refresh cycle.
  104. * (Based on S3 DirectDraw code)
  105. ****************************************************************************/
  106. #define NUM_VBLANKS_TO_MEASURE 1
  107. #define NUM_MEASUREMENTS_TO_TAKE 8
  108. VOID vGetDisplayDuration(PFLIPRECORD pflipRecord)
  109. {
  110. LONG i, j;
  111. LONGLONG li, liMin;
  112. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  113. DISPDBG((DBGLVL, "DDraw - vGetDisplayDuration\n"));
  114. #ifdef DBGBRK
  115. DBGBREAKPOINT();
  116. #endif
  117. memset(pflipRecord, 0, sizeof(FLIPRECORD));
  118. // Warm up EngQUeryPerformanceCounter to make sure it's in the working set
  119. EngQueryPerformanceCounter(&li);
  120. // Unfortunately, since NT is a proper multitasking system, we can't
  121. // just disable interrupts to take an accurate reading. We also can't
  122. // do anything so goofy as dynamically change our thread's priority to
  123. // real-time.
  124. //
  125. // So we just do a bunch of short measurements and take the minimum.
  126. //
  127. // It would be 'okay' if we got a result that's longer than the actual
  128. // VBlank cycle time -- nothing bad would happen except that the app
  129. // would run a little slower. We don't want to get a result that's
  130. // shorter than the actual VBlank cycle time -- that could cause us
  131. // to start drawing over a frame before the Flip has occured.
  132. while(IN_VBLANK);
  133. while(IN_DISPLAY);
  134. for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++)
  135. {
  136. // We're at the start of the VBlank active cycle!
  137. EngQueryPerformanceCounter(&aliMeasurement[i]);
  138. // Okay, so life in a multi-tasking environment isn't all that
  139. // simple. What if we had taken a context switch just before
  140. // the above EngQueryPerformanceCounter call, and now were half
  141. // way through the VBlank inactive cycle? Then we would measure
  142. // only half a VBlank cycle, which is obviously bad. The worst
  143. // thing we can do is get a time shorter than the actual VBlank
  144. // cycle time.
  145. //
  146. // So we solve this by making sure we're in the VBlank active
  147. // time before and after we query the time. If it's not, we'll
  148. // sync up to the next VBlank (it's okay to measure this period --
  149. // it will be guaranteed to be longer than the VBlank cycle and
  150. // will likely be thrown out when we select the minimum sample).
  151. // There's a chance that we'll take a context switch and return
  152. // just before the end of the active VBlank time -- meaning that
  153. // the actual measured time would be less than the true amount --
  154. // but since the VBlank is active less than 1% of the time, this
  155. // means that we would have a maximum of 1% error approximately
  156. // 1% of the times we take a context switch. An acceptable risk.
  157. //
  158. // This next line will cause us wait if we're no longer in the
  159. // VBlank active cycle as we should be at this point:
  160. while(IN_DISPLAY);
  161. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  162. {
  163. while(IN_VBLANK);
  164. while(IN_DISPLAY);
  165. };
  166. };
  167. EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
  168. // Use the minimum:
  169. liMin = aliMeasurement[1] - aliMeasurement[0];
  170. for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
  171. {
  172. li = aliMeasurement[i] - aliMeasurement[i - 1];
  173. if (li < liMin)
  174. liMin = li;
  175. };
  176. // Round the result:
  177. pflipRecord->liFlipDuration
  178. = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
  179. pflipRecord->liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE];
  180. pflipRecord->bFlipFlag = FALSE;
  181. pflipRecord->fpFlipFrom = 0;
  182. } // getDisplayDuration
  183. /****************************************************************************
  184. * FUNCTION NAME: vUpdateFlipStatus
  185. *
  186. * DESCRIPTION: Checks and sees if the most recent flip has occurred.
  187. * (Based on S3 DirectDraw code)
  188. ****************************************************************************/
  189. HRESULT vUpdateFlipStatus(PFLIPRECORD pflipRecord, FLATPTR fpVidMem)
  190. {
  191. LONGLONG liTime;
  192. DISPDBG((DBGLVL, "DDraw - vUpdateFlipStatus\n"));
  193. #ifdef DBGBRK
  194. DBGBREAKPOINT();
  195. #endif
  196. // see if a flip has happened recently
  197. if ((pflipRecord->bFlipFlag) &&
  198. ((fpVidMem == 0xFFFFFFFF) || (fpVidMem == pflipRecord->fpFlipFrom)))
  199. {
  200. if ((IN_VBLANK))
  201. {
  202. if (pflipRecord->bWasEverInDisplay)
  203. pflipRecord->bHaveEverCrossedVBlank = TRUE;
  204. }
  205. else if (!(IN_DISPLAYENABLE))
  206. {
  207. if (pflipRecord->bHaveEverCrossedVBlank)
  208. {
  209. pflipRecord->bFlipFlag = FALSE;
  210. return(DD_OK);
  211. };
  212. pflipRecord->bWasEverInDisplay = TRUE;
  213. };
  214. EngQueryPerformanceCounter(&liTime);
  215. if (liTime - pflipRecord->liFlipTime <= pflipRecord->liFlipDuration)
  216. {
  217. return(DDERR_WASSTILLDRAWING);
  218. };
  219. pflipRecord->bFlipFlag = FALSE;
  220. };
  221. return(DD_OK);
  222. } // updateFlipStatus
  223. /****************************************************************************
  224. * FUNCTION NAME: DdFlip
  225. *
  226. * DESCRIPTION:
  227. * (Based on S3 DirectDraw code)
  228. ****************************************************************************/
  229. DWORD DdFlip(PDD_FLIPDATA lpFlip)
  230. {
  231. DRIVERDATA* pDriverData;
  232. PDEV* ppdev;
  233. HRESULT ddrval;
  234. ULONG ulMemoryOffset;
  235. ULONG ulLowOffset;
  236. ULONG ulMiddleOffset;
  237. ULONG ulHighOffset;
  238. BYTE tmpb;
  239. DISPDBG((DBGLVL, "DDraw - DdFlip\n"));
  240. #ifdef DBGBRK
  241. DBGBREAKPOINT();
  242. #endif
  243. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  244. pDriverData = (DRIVERDATA*) &ppdev->DriverData;
  245. SYNC_W_3D(ppdev);
  246. #if DRIVER_5465 && defined(OVERLAY)
  247. if (DDSCAPS_OVERLAY & lpFlip->lpSurfCurr->ddsCaps.dwCaps)
  248. return pDriverData->OverlayTable.pfnFlip(ppdev,lpFlip);
  249. #endif
  250. // Is the current flip still in progress?
  251. // Don't want a flip to work until after the last flip is done,
  252. // so we ask for the general flip status.
  253. ddrval = vUpdateFlipStatus(&ppdev->flipRecord, 0xFFFFFFFF);
  254. if ((ddrval != DD_OK) || (DrawEngineBusy(pDriverData)))
  255. {
  256. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  257. return(DDHAL_DRIVER_HANDLED);
  258. };
  259. // everything is OK, do the flip here
  260. {
  261. DWORD dwOffset;
  262. // Determine the offset to the new area.
  263. dwOffset = lpFlip->lpSurfTarg->lpGbl->fpVidMem >> 2;
  264. // Make sure that the border/blanking period isn't active; wait if
  265. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  266. // that will increase the odds that we can't flip the next time:
  267. while (IN_DISPLAYENABLE)
  268. ;
  269. // Flip the primary surface by changing CRD, CRC, CR1B and CR1D
  270. // Do CRD last because the start address is double buffered and
  271. // will take effect after CRD is updated.
  272. // need bits 19 & 20 of address in bits 3 & 4 of CR1D
  273. tmpb = (BYTE) LLDR_SZ (grCR1D);
  274. tmpb = (tmpb & ~0x18) | (BYTE3FROMDWORD(dwOffset) & 0x18);
  275. LL8(grCR1D, tmpb);
  276. // need bits 16, 17 & 18 of address in bits 0, 2 & 3 of CR1B
  277. tmpb = (BYTE) LLDR_SZ (grCR1B);
  278. tmpb = (tmpb & ~0x0D) |
  279. ((((BYTE3FROMDWORD(dwOffset) & 0x06) << 1) |
  280. (BYTE3FROMDWORD(dwOffset) & 0x01)));
  281. LL8(grCR1B, tmpb);
  282. // bits 8-15 of address go in CRC
  283. LL8(grCRC, BYTE2FROMDWORD(dwOffset));
  284. // bits 0-7 of address go in CRD
  285. LL8(grCRD, BYTE1FROMDWORD(dwOffset));
  286. };
  287. // remember where/when we were when we did the flip
  288. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  289. ppdev->flipRecord.bFlipFlag = TRUE;
  290. ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
  291. ppdev->flipRecord.bWasEverInDisplay = FALSE;
  292. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  293. lpFlip->ddRVal = DD_OK;
  294. return(DDHAL_DRIVER_HANDLED);
  295. } // Flip
  296. /****************************************************************************
  297. * FUNCTION NAME: DdWaitForVerticalBlank
  298. *
  299. * DESCRIPTION:
  300. ****************************************************************************/
  301. DWORD DdWaitForVerticalBlank(PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  302. {
  303. PDEV* ppdev;
  304. DISPDBG((DBGLVL, "DDraw - DdWaitForVerticalBlank\n"));
  305. #ifdef DBGBRK
  306. DBGBREAKPOINT();
  307. #endif
  308. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  309. lpWaitForVerticalBlank->ddRVal = DD_OK;
  310. switch (lpWaitForVerticalBlank->dwFlags)
  311. {
  312. case DDWAITVB_I_TESTVB:
  313. // If TESTVB, it's just a request for the current vertical blank
  314. // status:
  315. lpWaitForVerticalBlank->bIsInVB = IN_VBLANK;
  316. return(DDHAL_DRIVER_HANDLED);
  317. case DDWAITVB_BLOCKBEGIN:
  318. // If BLOCKBEGIN is requested, we wait until the vertical blank
  319. // is over, and then wait for the display period to end:
  320. while(IN_VBLANK);
  321. while(IN_DISPLAY);
  322. return(DDHAL_DRIVER_HANDLED);
  323. case DDWAITVB_BLOCKEND:
  324. // If BLOCKEND is requested, we wait for the vblank interval to end:
  325. while(IN_DISPLAY);
  326. while(IN_VBLANK);
  327. return(DDHAL_DRIVER_HANDLED);
  328. default:
  329. return DDHAL_DRIVER_NOTHANDLED;
  330. }; // end switch
  331. return(DDHAL_DRIVER_NOTHANDLED);
  332. } // WaitForVerticalBlank
  333. /****************************************************************************
  334. * FUNCTION NAME: DdGetFlipStatus
  335. *
  336. * DESCRIPTION: If the display has gone through one refresh cycle since
  337. * the flip occurred, we return DD_OK. If it has not gone
  338. * through one refresh cycle we return DDERR_WASSTILLDRAWING
  339. * to indicate that this surface is still busy "drawing" the
  340. * flipped page. We also return DDERR_WASSTILLDRAWING if the
  341. * bltter is busy and the caller wanted to know if they could
  342. * flip yet.
  343. ****************************************************************************/
  344. DWORD DdGetFlipStatus(PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  345. {
  346. DRIVERDATA* pDriverData;
  347. PDEV* ppdev;
  348. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  349. pDriverData = (DRIVERDATA*) &ppdev->DriverData;
  350. DISPDBG((DBGLVL, "DDraw - DdGetFlipStatus\n"));
  351. #ifdef DBGBRK
  352. DBGBREAKPOINT();
  353. #endif
  354. SYNC_W_3D(ppdev);
  355. #if DRIVER_5465 && defined(OVERLAY)
  356. if (DDSCAPS_OVERLAY & lpGetFlipStatus->lpDDSurface->ddsCaps.dwCaps)
  357. {
  358. DWORD dwVWIndex;
  359. LP_SURFACE_DATA pSurfaceData = (LP_SURFACE_DATA) lpGetFlipStatus->lpDDSurface->dwReserved1;
  360. dwVWIndex = GetVideoWindowIndex(pSurfaceData->dwOverlayFlags);
  361. lpGetFlipStatus->ddRVal =
  362. pDriverData->OverlayTable.pfnGetFlipStatus(ppdev,
  363. lpGetFlipStatus->lpDDSurface->lpGbl->fpVidMem,
  364. dwVWIndex);
  365. }
  366. else
  367. #endif
  368. {
  369. // We don't want a flip to work until after the last flip is done,
  370. // so we ask for the general flip status.
  371. lpGetFlipStatus->ddRVal = vUpdateFlipStatus(&ppdev->flipRecord, 0xFFFFFFFF);
  372. }
  373. // Check if the bltter is busy if someone wants to know if they can flip
  374. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  375. {
  376. if ((lpGetFlipStatus->ddRVal == DD_OK) && DrawEngineBusy(pDriverData))
  377. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  378. }
  379. return(DDHAL_DRIVER_HANDLED);
  380. } // GetFlipStatus
  381. // #ifdef DDDRV_GETSCANLINE /************/
  382. /****************************************************************************
  383. * FUNCTION NAME: GetScanLine
  384. *
  385. * DESCRIPTION:
  386. * (Based on Laguna Win95 DirectDraw code)
  387. ****************************************************************************/
  388. DWORD GetScanLine(PDD_GETSCANLINEDATA lpGetScanLine)
  389. {
  390. PDEV* ppdev;
  391. ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
  392. // If a vertical blank is in progress the scan line is in
  393. // indeterminant. If the scan line is indeterminant we return
  394. // the error code DDERR_VERTICALBLANKINPROGRESS.
  395. // Otherwise we return the scan line and a success code
  396. SYNC_W_3D(ppdev); // if 3D context(s) active, make sure 3D engine idle before continuing...
  397. if (IN_VBLANK)
  398. {
  399. lpGetScanLine->ddRVal = DDERR_VERTICALBLANKINPROGRESS;
  400. }
  401. else
  402. {
  403. lpGetScanLine->dwScanLine = CurrentVLine(ppdev);
  404. lpGetScanLine->ddRVal = DD_OK;
  405. };
  406. return DDHAL_DRIVER_HANDLED;
  407. } // GetScanLine
  408. // #endif // DDDRV_GETSCANLINE ************
  409. #endif // ! ver 3.51
  410. 
  411.