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.

1130 lines
34 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: ddraw.c
  3. *
  4. * Implements all the DirectDraw components for the driver.
  5. *
  6. * Copyright (c) 1995-1996 Microsoft Corporation
  7. \**************************************************************************/
  8. #include "precomp.h"
  9. // NT is kind enough to pre-calculate the 2-d surface offset as a 'hint' so
  10. // that we don't have to do the following, which would be 6 DIVs per blt:
  11. //
  12. // y += (offset / pitch)
  13. // x += (offset % pitch) / bytes_per_pixel
  14. #define convertToGlobalCord(x, y, surf) \
  15. { \
  16. y += surf->yHint; \
  17. x += surf->xHint; \
  18. }
  19. /////////////////////////////////////////////////////////////////
  20. // DirectDraw stuff
  21. #define VBLANK_IS_ACTIVE(pjPorts)\
  22. ((CP_IN_BYTE(pjPorts, STATUS_1) & 0x08) ? TRUE : FALSE) // !!! 0x3da
  23. #define DISPLAY_IS_ACTIVE(pjPorts)\
  24. ((CP_IN_BYTE(pjPorts, STATUS_1) & 0x01) ? TRUE : FALSE)
  25. #define ENTER(s) DISPDBG((10, "Entering "#s));
  26. #define EXIT(s) DISPDBG((10, "Exiting "#s" line(%d)", __LINE__));
  27. /******************************Public*Routine******************************\
  28. * VOID vGetDisplayDuration
  29. *
  30. * Get the length, in EngQueryPerformanceCounter() ticks, of a refresh cycle.
  31. *
  32. * If we could trust the miniport to return back and accurate value for
  33. * the refresh rate, we could use that. Unfortunately, our miniport doesn't
  34. * ensure that it's an accurate value.
  35. *
  36. \**************************************************************************/
  37. #define NUM_VBLANKS_TO_MEASURE 1
  38. #define NUM_MEASUREMENTS_TO_TAKE 10
  39. #define NUM_MEASUREMENTS_TO_DISCARD 3
  40. #if (NUM_MEASUREMENTS_TO_TAKE - NUM_MEASUREMENTS_TO_DISCARD) < 2
  41. #error ***************************************
  42. #error *** You discarded too many measurements
  43. #error ***************************************
  44. #endif
  45. VOID vGetDisplayDuration(PDEV* ppdev)
  46. {
  47. BYTE* pjBase;
  48. BYTE* pjPorts;
  49. LONG i;
  50. LONG j;
  51. LONGLONG li;
  52. LONGLONG liMin;
  53. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  54. pjBase = ppdev->pjBase;
  55. pjPorts = ppdev->pjPorts;
  56. memset(&ppdev->flipRecord, 0, sizeof(ppdev->flipRecord));
  57. // Warm up EngQUeryPerformanceCounter to make sure it's in the working
  58. // set:
  59. EngQueryPerformanceCounter(&li);
  60. // Unfortunately, since NT is a proper multitasking system, we can't
  61. // just disable interrupts to take an accurate reading. We also can't
  62. // do anything so goofy as dynamically change our thread's priority to
  63. // real-time.
  64. //
  65. // So we just do a bunch of short measurements and take the minimum.
  66. //
  67. // It would be 'okay' if we got a result that's longer than the actual
  68. // VBlank cycle time -- nothing bad would happen except that the app
  69. // would run a little slower. We don't want to get a result that's
  70. // shorter than the actual VBlank cycle time -- that could cause us
  71. // to start drawing over a frame before the Flip has occured.
  72. while (VBLANK_IS_ACTIVE(pjPorts))
  73. ;
  74. while (!(VBLANK_IS_ACTIVE(pjPorts)))
  75. ;
  76. for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++)
  77. {
  78. // We're at the start of the VBlank active cycle!
  79. EngQueryPerformanceCounter(&aliMeasurement[i]);
  80. // Okay, so life in a multi-tasking environment isn't all that
  81. // simple. What if we had taken a context switch just before
  82. // the above EngQueryPerformanceCounter call, and now were half
  83. // way through the VBlank inactive cycle? Then we would measure
  84. // only half a VBlank cycle, which is obviously bad. The worst
  85. // thing we can do is get a time shorter than the actual VBlank
  86. // cycle time.
  87. //
  88. // So we solve this by making sure we're in the VBlank active
  89. // time before and after we query the time. If it's not, we'll
  90. // sync up to the next VBlank (it's okay to measure this period --
  91. // it will be guaranteed to be longer than the VBlank cycle and
  92. // will likely be thrown out when we select the minimum sample).
  93. // There's a chance that we'll take a context switch and return
  94. // just before the end of the active VBlank time -- meaning that
  95. // the actual measured time would be less than the true amount --
  96. // but since the VBlank is active less than 1% of the time, this
  97. // means that we would have a maximum of 1% error approximately
  98. // 1% of the times we take a context switch. An acceptable risk.
  99. //
  100. // This next line will cause us wait if we're no longer in the
  101. // VBlank active cycle as we should be at this point:
  102. while (!(VBLANK_IS_ACTIVE(pjPorts)))
  103. ;
  104. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  105. {
  106. while (VBLANK_IS_ACTIVE(pjPorts))
  107. ;
  108. while (!(VBLANK_IS_ACTIVE(pjPorts)))
  109. ;
  110. }
  111. }
  112. EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
  113. // Use the minimum:
  114. liMin = aliMeasurement[1+NUM_MEASUREMENTS_TO_DISCARD] -
  115. aliMeasurement[0+NUM_MEASUREMENTS_TO_DISCARD];
  116. DISPDBG((1, "Refresh count: %li - %li", 1, (ULONG) liMin));
  117. for (i = 2+NUM_MEASUREMENTS_TO_DISCARD; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
  118. {
  119. li = aliMeasurement[i] - aliMeasurement[i - 1];
  120. DISPDBG((1, " %li - %li", i - NUM_MEASUREMENTS_TO_DISCARD, (ULONG) li));
  121. if (li < liMin)
  122. liMin = li;
  123. }
  124. // Round the result:
  125. ppdev->flipRecord.liFlipDuration
  126. = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
  127. DISPDBG((1, "Frequency %li.%03li Hz",
  128. (ULONG) (EngQueryPerformanceFrequency(&li),
  129. li / ppdev->flipRecord.liFlipDuration),
  130. (ULONG) (EngQueryPerformanceFrequency(&li),
  131. ((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
  132. ppdev->flipRecord.liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE];
  133. ppdev->flipRecord.bFlipFlag = FALSE;
  134. ppdev->flipRecord.fpFlipFrom = 0;
  135. }
  136. /******************************Public*Routine******************************\
  137. * HRESULT vUpdateFlipStatus
  138. *
  139. * Checks and sees if the most recent flip has occurred.
  140. *
  141. \**************************************************************************/
  142. HRESULT vUpdateFlipStatus(
  143. PDEV* ppdev,
  144. FLATPTR fpVidMem)
  145. {
  146. BYTE* pjBase;
  147. BYTE* pjPorts;
  148. LONGLONG liTime;
  149. ENTER(vUpdateFlipStatus);
  150. pjBase = ppdev->pjBase;
  151. pjPorts = ppdev->pjPorts;
  152. if ((ppdev->flipRecord.bFlipFlag) &&
  153. ((fpVidMem == 0) || (fpVidMem == ppdev->flipRecord.fpFlipFrom)))
  154. {
  155. if (VBLANK_IS_ACTIVE(pjPorts))
  156. {
  157. if (ppdev->flipRecord.bWasEverInDisplay)
  158. {
  159. ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE;
  160. }
  161. }
  162. else if (DISPLAY_IS_ACTIVE(pjPorts))
  163. {
  164. if( ppdev->flipRecord.bHaveEverCrossedVBlank )
  165. {
  166. ppdev->flipRecord.bFlipFlag = FALSE;
  167. EXIT(vUpdateFlipStatus);
  168. return(DD_OK);
  169. }
  170. ppdev->flipRecord.bWasEverInDisplay = TRUE;
  171. }
  172. EngQueryPerformanceCounter(&liTime);
  173. if (liTime - ppdev->flipRecord.liFlipTime
  174. <= ppdev->flipRecord.liFlipDuration)
  175. {
  176. EXIT(vUpdateFlipStatus);
  177. return(DDERR_WASSTILLDRAWING);
  178. }
  179. ppdev->flipRecord.bFlipFlag = FALSE;
  180. }
  181. EXIT(vUpdateFlipStatus);
  182. return(DD_OK);
  183. }
  184. /******************************Public*Routine******************************\
  185. * DWORD DdBlt
  186. *
  187. \**************************************************************************/
  188. DWORD DdBlt(
  189. PDD_BLTDATA lpBlt)
  190. {
  191. PDD_SURFACE_GLOBAL srcSurf;
  192. PDD_SURFACE_LOCAL destSurfx;
  193. PDD_SURFACE_GLOBAL destSurf;
  194. PDEV* ppdev;
  195. BYTE* pjBase;
  196. HRESULT ddrval;
  197. FLATPTR destOffset;
  198. DWORD destPitch;
  199. DWORD destX;
  200. DWORD destY;
  201. DWORD direction;
  202. DWORD dwFlags;
  203. DWORD height;
  204. BYTE rop;
  205. FLATPTR sourceOffset;
  206. DWORD srcPitch;
  207. DWORD srcX;
  208. DWORD srcY;
  209. DWORD width;
  210. LONG lDelta;
  211. LONG cBpp;
  212. ULONG ulBltAdjust = 0;
  213. ENTER(DdBlt);
  214. ppdev = (PDEV*) lpBlt->lpDD->dhpdev;
  215. pjBase = ppdev->pjBase;
  216. lDelta = ppdev->lDelta;
  217. cBpp = ppdev->cBpp;
  218. destSurfx = lpBlt->lpDDDestSurface;
  219. destSurf = destSurfx->lpGbl;
  220. // Is a flip in progress?
  221. ddrval = vUpdateFlipStatus(ppdev, destSurf->fpVidMem);
  222. if (ddrval != DD_OK)
  223. {
  224. lpBlt->ddRVal = ddrval;
  225. EXIT(DdBlt);
  226. return(DDHAL_DRIVER_HANDLED);
  227. }
  228. dwFlags = lpBlt->dwFlags;
  229. if (dwFlags & DDBLT_ASYNC)
  230. {
  231. // If async, then only work if we won't have to wait on the
  232. // accelerator to start the command.
  233. // !!! is this next line correct?
  234. if (IS_BUSY(ppdev, pjBase))
  235. {
  236. lpBlt->ddRVal = DDERR_WASSTILLDRAWING;
  237. EXIT(DdBlt);
  238. return(DDHAL_DRIVER_HANDLED);
  239. }
  240. }
  241. // Copy src/dest rects:
  242. destX = lpBlt->rDest.left;
  243. destY = lpBlt->rDest.top;
  244. width = lpBlt->rDest.right - lpBlt->rDest.left;
  245. height = lpBlt->rDest.bottom - lpBlt->rDest.top;
  246. destPitch = destSurf->lPitch;
  247. destOffset = destSurf->fpVidMem;
  248. if (dwFlags & DDBLT_COLORFILL)
  249. {
  250. lpBlt->ddRVal = DD_OK;
  251. convertToGlobalCord(destX, destY, destSurf);
  252. // Solid fill here
  253. {
  254. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  255. CP_FG_ROP(ppdev, pjBase, R3_PATCOPY);
  256. CP_DST_Y_OFFSET(ppdev, pjBase, (lDelta - 1));
  257. CP_PAT_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset);
  258. CP_XCNT(ppdev, pjBase, (width * cBpp - 1));
  259. CP_YCNT(ppdev, pjBase, (height - 1));
  260. WAIT_FOR_IDLE_ACL(ppdev, pjBase);
  261. *(PULONG)(ppdev->pjScreen + ppdev->ulSolidColorOffset) =
  262. COLOR_REPLICATE(ppdev, lpBlt->bltFX.dwFillColor);
  263. if (cBpp == 3)
  264. {
  265. CP_PEL_DEPTH(ppdev, pjBase, HW_PEL_DEPTH_24BPP);
  266. CP_PAT_WRAP(ppdev, pjBase, SOLID_COLOR_PATTERN_WRAP_24BPP);
  267. CP_PAT_Y_OFFSET(ppdev, pjBase, (SOLID_COLOR_PATTERN_OFFSET_24BPP - 1));
  268. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX)));
  269. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  270. CP_PEL_DEPTH(ppdev, pjBase, HW_PEL_DEPTH_8BPP);
  271. }
  272. else
  273. {
  274. CP_PAT_WRAP(ppdev, pjBase, SOLID_COLOR_PATTERN_WRAP);
  275. CP_PAT_Y_OFFSET(ppdev, pjBase, (SOLID_COLOR_PATTERN_OFFSET - 1));
  276. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX)));
  277. }
  278. }
  279. EXIT(DdBlt);
  280. return(DDHAL_DRIVER_HANDLED);
  281. }
  282. // We specified with Our ddCaps.dwCaps that we handle a limited number
  283. // of commands, and by this point in our routine we've handled everything
  284. // except DDBLT_ROP. DirectDraw and GDI shouldn't pass us anything
  285. // else; we'll assert on debug builds to prove this:
  286. ASSERTDD((dwFlags & DDBLT_ROP) && (lpBlt->lpDDSrcSurface),
  287. "Expected dwFlags commands of only DDBLT_ASYNC and DDBLT_COLORFILL");
  288. // Get offset, width, and height for source:
  289. srcSurf = lpBlt->lpDDSrcSurface->lpGbl;
  290. srcX = lpBlt->rSrc.left;
  291. srcY = lpBlt->rSrc.top;
  292. srcPitch = srcSurf->lPitch;
  293. sourceOffset = srcSurf->fpVidMem;
  294. // Assume we can do the blt top-to-bottom, left-to-right:
  295. if ((destSurf == srcSurf) && (srcX + width > destX) &&
  296. (srcY + height > destY) && (destX + width > srcX) &&
  297. (destY + height > srcY) &&
  298. (((srcY == destY) && (destX > srcX) )
  299. || ((srcY != destY) && (destY > srcY))))
  300. {
  301. // Okay, we have to do the blt bottom-to-top, right-to-left:
  302. ulBltAdjust = 1;
  303. srcX = lpBlt->rSrc.right;
  304. srcY = lpBlt->rSrc.bottom - 1;
  305. destX = lpBlt->rDest.right;
  306. destY = lpBlt->rDest.bottom - 1;
  307. }
  308. // NT only ever gives us SRCCOPY rops, so don't even both checking
  309. // for anything else.
  310. convertToGlobalCord(srcX, srcY, srcSurf);
  311. convertToGlobalCord(destX, destY, destSurf);
  312. // Bitmap Blt
  313. {
  314. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  315. if (ulBltAdjust) {
  316. CP_XY_DIR(ppdev, pjBase, (BOTTOM_TO_TOP | RIGHT_TO_LEFT));
  317. }
  318. if (dwFlags & DDBLT_KEYSRCOVERRIDE)
  319. {
  320. // Color keyed Transparency
  321. CP_FG_ROP(ppdev, pjBase, R3_SRCCOPY);
  322. CP_SRC_WRAP(ppdev, pjBase, NO_PATTERN_WRAP);
  323. CP_SRC_Y_OFFSET(ppdev, pjBase, (lDelta - 1));
  324. CP_DST_Y_OFFSET(ppdev, pjBase, (lDelta - 1));
  325. if (ulBltAdjust) {
  326. CP_PAT_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset + cBpp - 1);
  327. } else {
  328. CP_PAT_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset);
  329. }
  330. CP_ROUTING_CTRL(ppdev, pjBase, 0x13); // Generate CompareMap
  331. CP_XCNT(ppdev, pjBase, ((cBpp * width) - 1));
  332. CP_YCNT(ppdev, pjBase, (height - 1));
  333. CP_SRC_ADDR(ppdev, pjBase, ((srcY * lDelta) + (cBpp * srcX) - ulBltAdjust));
  334. WAIT_FOR_IDLE_ACL(ppdev, pjBase);
  335. *(PULONG)(ppdev->pjScreen + ppdev->ulSolidColorOffset) =
  336. COLOR_REPLICATE(ppdev, lpBlt->bltFX.ddckSrcColorkey.dwColorSpaceLowValue);
  337. if (cBpp == 3)
  338. {
  339. CP_PEL_DEPTH(ppdev, pjBase, HW_PEL_DEPTH_24BPP);
  340. CP_PAT_WRAP(ppdev, pjBase, SOLID_COLOR_PATTERN_WRAP_24BPP);
  341. CP_PAT_Y_OFFSET(ppdev, pjBase, (SOLID_COLOR_PATTERN_OFFSET_24BPP - 1));
  342. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX) - ulBltAdjust));
  343. }
  344. else if (cBpp == 2)
  345. {
  346. CP_PEL_DEPTH(ppdev, pjBase, HW_PEL_DEPTH_16BPP);
  347. CP_PAT_WRAP(ppdev, pjBase, SOLID_COLOR_PATTERN_WRAP);
  348. CP_PAT_Y_OFFSET(ppdev, pjBase, (SOLID_COLOR_PATTERN_OFFSET - 1));
  349. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX) - ulBltAdjust));
  350. }
  351. else
  352. {
  353. CP_PAT_WRAP(ppdev, pjBase, SOLID_COLOR_PATTERN_WRAP);
  354. CP_PAT_Y_OFFSET(ppdev, pjBase, (SOLID_COLOR_PATTERN_OFFSET - 1));
  355. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX) - ulBltAdjust));
  356. }
  357. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  358. CP_PEL_DEPTH(ppdev, pjBase, HW_PEL_DEPTH_8BPP);
  359. CP_ROUTING_CTRL(ppdev, pjBase, 0x33);
  360. }
  361. else
  362. {
  363. // Opaque
  364. CP_FG_ROP(ppdev, pjBase, R3_SRCCOPY);
  365. CP_SRC_WRAP(ppdev, pjBase, NO_PATTERN_WRAP);
  366. CP_SRC_Y_OFFSET(ppdev, pjBase, (lDelta - 1));
  367. CP_DST_Y_OFFSET(ppdev, pjBase, (lDelta - 1));
  368. CP_XCNT(ppdev, pjBase, ((cBpp * width) - 1));
  369. CP_YCNT(ppdev, pjBase, (height - 1));
  370. CP_SRC_ADDR(ppdev, pjBase, ((srcY * lDelta) + (cBpp * srcX) - ulBltAdjust));
  371. CP_DST_ADDR(ppdev, pjBase, ((destY * lDelta) + (cBpp * destX) - ulBltAdjust));
  372. }
  373. if (ulBltAdjust) {
  374. WAIT_FOR_EMPTY_ACL_QUEUE(ppdev, pjBase);
  375. CP_XY_DIR(ppdev, pjBase, 0);
  376. }
  377. }
  378. lpBlt->ddRVal = DD_OK;
  379. EXIT(DdBlt);
  380. return(DDHAL_DRIVER_HANDLED);
  381. }
  382. /******************************Public*Routine******************************\
  383. * DWORD DdFlip
  384. *
  385. \**************************************************************************/
  386. DWORD DdFlip(
  387. PDD_FLIPDATA lpFlip)
  388. {
  389. PDEV* ppdev;
  390. BYTE* pjBase;
  391. BYTE* pjPorts;
  392. HRESULT ddrval;
  393. ULONG ulMemoryOffset;
  394. ULONG ulLowOffset;
  395. ULONG ulMiddleOffset;
  396. ULONG ulHighOffset;
  397. ENTER(DdFLip);
  398. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  399. pjBase = ppdev->pjBase;
  400. pjPorts = ppdev->pjPorts;
  401. // Is the current flip still in progress?
  402. //
  403. // Don't want a flip to work until after the last flip is done,
  404. // so we ask for the general flip status and ignore the vmem.
  405. ddrval = vUpdateFlipStatus(ppdev, 0);
  406. if ((ddrval != DD_OK) || (IS_BUSY(ppdev, pjBase)))
  407. {
  408. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  409. EXIT(DdFLip);
  410. return(DDHAL_DRIVER_HANDLED);
  411. }
  412. // Do the flip:
  413. ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem) >> 2;
  414. ulLowOffset = 0x0d | ((ulMemoryOffset & 0x0000ff) << 8);
  415. ulMiddleOffset = 0x0c | ((ulMemoryOffset & 0x00ff00));
  416. ulHighOffset = 0x33 | ((ulMemoryOffset & 0x0f0000) >> 8);
  417. // Make sure that the border/blanking period isn't active; wait if
  418. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  419. // that will increase the odds that we can't flip the next time:
  420. while (!(DISPLAY_IS_ACTIVE(pjPorts)))
  421. ;
  422. CP_OUT_WORD(pjPorts, CRTC_INDEX, ulLowOffset);
  423. CP_OUT_WORD(pjPorts, CRTC_INDEX, ulMiddleOffset);
  424. CP_OUT_WORD(pjPorts, CRTC_INDEX, ulHighOffset);
  425. // Remember where and when we were when we did the flip:
  426. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  427. ppdev->flipRecord.bFlipFlag = TRUE;
  428. ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
  429. ppdev->flipRecord.bWasEverInDisplay = FALSE;
  430. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  431. lpFlip->ddRVal = DD_OK;
  432. EXIT(DdFLip);
  433. return(DDHAL_DRIVER_HANDLED);
  434. }
  435. /******************************Public*Routine******************************\
  436. * DWORD DdLock
  437. *
  438. \**************************************************************************/
  439. DWORD DdLock(
  440. PDD_LOCKDATA lpLock)
  441. {
  442. PDEV* ppdev;
  443. BYTE* pjBase;
  444. HRESULT ddrval;
  445. ENTER(DdLock);
  446. ppdev = (PDEV*) lpLock->lpDD->dhpdev;
  447. pjBase = ppdev->pjBase;
  448. // Check to see if any pending physical flip has occurred.
  449. // Don't allow a lock if a blt is in progress:
  450. ddrval = vUpdateFlipStatus(ppdev, lpLock->lpDDSurface->lpGbl->fpVidMem);
  451. if (ddrval != DD_OK)
  452. {
  453. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  454. EXIT(DdLock);
  455. return(DDHAL_DRIVER_HANDLED);
  456. }
  457. if ((ppdev->dwLinearCnt == 0) && (IS_BUSY(ppdev, pjBase)))
  458. {
  459. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  460. return(DDHAL_DRIVER_HANDLED);
  461. }
  462. // Reference count it, just for the heck of it:
  463. ppdev->dwLinearCnt++;
  464. EXIT(DdLock);
  465. return(DDHAL_DRIVER_NOTHANDLED);
  466. }
  467. /******************************Public*Routine******************************\
  468. * DWORD DdUnlock
  469. *
  470. \**************************************************************************/
  471. DWORD DdUnlock(
  472. PDD_UNLOCKDATA lpUnlock)
  473. {
  474. PDEV* ppdev;
  475. ENTER(DdUnlock);
  476. ppdev = (PDEV*) lpUnlock->lpDD->dhpdev;
  477. ppdev->dwLinearCnt--;
  478. EXIT(DdUnlock);
  479. return(DDHAL_DRIVER_NOTHANDLED);
  480. }
  481. /******************************Public*Routine******************************\
  482. * DWORD DdGetBltStatus
  483. *
  484. * Doesn't currently really care what surface is specified, just checks
  485. * and goes.
  486. *
  487. \**************************************************************************/
  488. DWORD DdGetBltStatus(
  489. PDD_GETBLTSTATUSDATA lpGetBltStatus)
  490. {
  491. PDEV* ppdev;
  492. BYTE* pjBase;
  493. HRESULT ddRVal;
  494. ENTER(DdGetBltStatus);
  495. ppdev = (PDEV*) lpGetBltStatus->lpDD->dhpdev;
  496. pjBase = ppdev->pjBase;
  497. ddRVal = DD_OK;
  498. if (lpGetBltStatus->dwFlags == DDGBS_CANBLT)
  499. {
  500. // DDGBS_CANBLT case: can we add a blt?
  501. ddRVal = vUpdateFlipStatus(ppdev,
  502. lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
  503. if (ddRVal == DD_OK)
  504. {
  505. // There was no flip going on, so is there room in the FIFO
  506. // to add a blt?
  507. // !!! is this next line correct?
  508. if (IS_BUSY(ppdev, pjBase))
  509. {
  510. ddRVal = DDERR_WASSTILLDRAWING;
  511. }
  512. }
  513. }
  514. else
  515. {
  516. // DDGBS_ISBLTDONE case: is a blt in progress?
  517. if (IS_BUSY(ppdev, pjBase))
  518. {
  519. ddRVal = DDERR_WASSTILLDRAWING;
  520. }
  521. }
  522. lpGetBltStatus->ddRVal = ddRVal;
  523. EXIT(DdGetBltStatus);
  524. return(DDHAL_DRIVER_HANDLED);
  525. }
  526. /******************************Public*Routine******************************\
  527. * DWORD DdMapMemory
  528. *
  529. * This is a new DDI call specific to Windows NT that is used to map
  530. * or unmap all the application modifiable portions of the frame buffer
  531. * into the specified process's address space.
  532. *
  533. \**************************************************************************/
  534. DWORD DdMapMemory(
  535. PDD_MAPMEMORYDATA lpMapMemory)
  536. {
  537. PDEV* ppdev;
  538. VIDEO_SHARE_MEMORY ShareMemory;
  539. VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation;
  540. DWORD ReturnedDataLength;
  541. ENTER(DdMapMemory);
  542. ppdev = (PDEV*) lpMapMemory->lpDD->dhpdev;
  543. if (lpMapMemory->bMap)
  544. {
  545. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  546. // 'RequestedVirtualAddress' isn't actually used for the SHARE IOCTL:
  547. ShareMemory.RequestedVirtualAddress = 0;
  548. // We map in starting at the top of the frame buffer:
  549. ShareMemory.ViewOffset = 0;
  550. // We map down to the end of the frame buffer.
  551. //
  552. // Note: There is a 64k granularity on the mapping (meaning that
  553. // we have to round up to 64k).
  554. //
  555. // Note: If there is any portion of the frame buffer that must
  556. // not be modified by an application, that portion of memory
  557. // MUST NOT be mapped in by this call. This would include
  558. // any data that, if modified by a malicious application,
  559. // would cause the driver to crash. This could include, for
  560. // example, any DSP code that is kept in off-screen memory.
  561. ShareMemory.ViewSize
  562. = ROUND_UP_TO_64K(ppdev->cyMemory * ppdev->lDelta);
  563. if (EngDeviceIoControl(ppdev->hDriver,
  564. IOCTL_VIDEO_SHARE_VIDEO_MEMORY,
  565. &ShareMemory,
  566. sizeof(VIDEO_SHARE_MEMORY),
  567. &ShareMemoryInformation,
  568. sizeof(VIDEO_SHARE_MEMORY_INFORMATION),
  569. &ReturnedDataLength))
  570. {
  571. DISPDBG((0, "Failed IOCTL_VIDEO_SHARE_MEMORY"));
  572. lpMapMemory->ddRVal = DDERR_GENERIC;
  573. EXIT(DdMapMemory);
  574. return(DDHAL_DRIVER_HANDLED);
  575. }
  576. lpMapMemory->fpProcess = (ULONG_PTR) ShareMemoryInformation.VirtualAddress;
  577. }
  578. else
  579. {
  580. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  581. ShareMemory.ViewOffset = 0;
  582. ShareMemory.ViewSize = 0;
  583. ShareMemory.RequestedVirtualAddress = (VOID*) lpMapMemory->fpProcess;
  584. if (EngDeviceIoControl(ppdev->hDriver,
  585. IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY,
  586. &ShareMemory,
  587. sizeof(VIDEO_SHARE_MEMORY),
  588. NULL,
  589. 0,
  590. &ReturnedDataLength))
  591. {
  592. RIP("Failed IOCTL_VIDEO_UNSHARE_MEMORY");
  593. }
  594. }
  595. lpMapMemory->ddRVal = DD_OK;
  596. EXIT(DdMapMemory);
  597. return(DDHAL_DRIVER_HANDLED);
  598. }
  599. /******************************Public*Routine******************************\
  600. * DWORD DdGetFlipStatus
  601. *
  602. * If the display has gone through one refresh cycle since the flip
  603. * occurred, we return DD_OK. If it has not gone through one refresh
  604. * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
  605. * is still busy "drawing" the flipped page. We also return
  606. * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted
  607. * to know if they could flip yet.
  608. *
  609. \**************************************************************************/
  610. DWORD DdGetFlipStatus(
  611. PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  612. {
  613. PDEV* ppdev;
  614. BYTE* pjBase;
  615. ENTER(DdGetFlipStatus);
  616. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  617. pjBase = ppdev->pjBase;
  618. // We don't want a flip to work until after the last flip is done,
  619. // so we ask for the general flip status and ignore the vmem:
  620. lpGetFlipStatus->ddRVal = vUpdateFlipStatus(ppdev, 0);
  621. // Check if the bltter is busy if someone wants to know if they can
  622. // flip:
  623. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  624. {
  625. if ((lpGetFlipStatus->ddRVal == DD_OK) && (IS_BUSY(ppdev, pjBase)))
  626. {
  627. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  628. }
  629. }
  630. EXIT(DdGetFlipStatus);
  631. return(DDHAL_DRIVER_HANDLED);
  632. }
  633. /******************************Public*Routine******************************\
  634. * DWORD DdWaitForVerticalBlank
  635. *
  636. \**************************************************************************/
  637. DWORD DdWaitForVerticalBlank(
  638. PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  639. {
  640. PDEV* ppdev;
  641. BYTE* pjBase;
  642. BYTE* pjPorts;
  643. ENTER(DdWaitForVerticalBlank);
  644. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  645. pjBase = ppdev->pjBase;
  646. pjPorts = ppdev->pjPorts;
  647. lpWaitForVerticalBlank->ddRVal = DD_OK;
  648. switch (lpWaitForVerticalBlank->dwFlags)
  649. {
  650. case DDWAITVB_I_TESTVB:
  651. // If TESTVB, it's just a request for the current vertical blank
  652. // status:
  653. if (VBLANK_IS_ACTIVE(pjPorts))
  654. lpWaitForVerticalBlank->bIsInVB = TRUE;
  655. else
  656. lpWaitForVerticalBlank->bIsInVB = FALSE;
  657. EXIT(DdWaitForVerticalBlank);
  658. return(DDHAL_DRIVER_HANDLED);
  659. case DDWAITVB_BLOCKBEGIN:
  660. // If BLOCKBEGIN is requested, we wait until the vertical blank
  661. // is over, and then wait for the display period to end:
  662. while (VBLANK_IS_ACTIVE(pjPorts))
  663. ;
  664. while (!(VBLANK_IS_ACTIVE(pjPorts)))
  665. ;
  666. EXIT(DdWaitForVerticalBlank);
  667. return(DDHAL_DRIVER_HANDLED);
  668. case DDWAITVB_BLOCKEND:
  669. // If BLOCKEND is requested, we wait for the vblank interval to end:
  670. while (!(VBLANK_IS_ACTIVE(pjPorts)))
  671. ;
  672. while (VBLANK_IS_ACTIVE(pjPorts))
  673. ;
  674. EXIT(DdWaitForVerticalBlank);
  675. return(DDHAL_DRIVER_HANDLED);
  676. }
  677. EXIT(DdWaitForVerticalBlank);
  678. return(DDHAL_DRIVER_NOTHANDLED);
  679. }
  680. /******************************Public*Routine******************************\
  681. * BOOL DrvGetDirectDrawInfo
  682. *
  683. * Will be called before DrvEnableDirectDraw is called.
  684. *
  685. \**************************************************************************/
  686. BOOL DrvGetDirectDrawInfo(
  687. DHPDEV dhpdev,
  688. DD_HALINFO* pHalInfo,
  689. DWORD* pdwNumHeaps,
  690. VIDEOMEMORY* pvmList, // Will be NULL on first call
  691. DWORD* pdwNumFourCC,
  692. DWORD* pdwFourCC) // Will be NULL on first call
  693. {
  694. BOOL bCanFlip;
  695. PDEV* ppdev;
  696. LONGLONG li;
  697. OH* poh;
  698. ENTER(DrvGetDirectDrawInfo);
  699. ppdev = (PDEV*) dhpdev;
  700. // We may not support DirectDraw on this card:
  701. if (!(ppdev->flStatus & STAT_DIRECTDRAW))
  702. {
  703. EXIT(DrvGetDirectDrawInfo);
  704. return(FALSE);
  705. }
  706. pHalInfo->dwSize = sizeof(*pHalInfo);
  707. // Current primary surface attributes. Since HalInfo is zero-initialized
  708. // by GDI, we only have to fill in the fields which should be non-zero:
  709. pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
  710. pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen;
  711. pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
  712. pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta;
  713. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  714. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  715. // !!! What about 15 vs. 16 Bpp below?
  716. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cBpp * 8;
  717. if (ppdev->iBitmapFormat == BMF_8BPP)
  718. {
  719. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  720. }
  721. // These masks will be zero at 8bpp:
  722. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed;
  723. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen;
  724. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
  725. if (ppdev->iBitmapFormat == BMF_32BPP)
  726. {
  727. pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask
  728. = ~(ppdev->flRed | ppdev->flGreen | ppdev->flBlue);
  729. }
  730. else
  731. {
  732. pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = 0;
  733. }
  734. // Set up the pointer to the first available video memory after
  735. // the primary surface:
  736. bCanFlip = FALSE;
  737. *pdwNumHeaps = 0;
  738. // Free up as much off-screen memory as possible:
  739. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  740. // Now simply reserve the biggest chunk for use by DirectDraw:
  741. poh = ppdev->pohDirectDraw;
  742. if (poh == NULL)
  743. {
  744. poh = pohAllocate(ppdev,
  745. NULL,
  746. ppdev->heap.cxMax,
  747. ppdev->heap.cyMax,
  748. FLOH_MAKE_PERMANENT);
  749. ppdev->pohDirectDraw = poh;
  750. }
  751. if (poh != NULL)
  752. {
  753. *pdwNumHeaps = 1;
  754. // Fill in the list of off-screen rectangles if we've been asked
  755. // to do so:
  756. if (pvmList != NULL)
  757. {
  758. DISPDBG((1, "DirectDraw gets %li x %li surface at (%li, %li)",
  759. poh->cx, poh->cy, poh->x, poh->y));
  760. pvmList->dwFlags = VIDMEM_ISRECTANGULAR;
  761. pvmList->fpStart = (poh->y * ppdev->lDelta)
  762. + (poh->x * ppdev->cBpp);
  763. pvmList->dwWidth = poh->cx * ppdev->cBpp;
  764. pvmList->dwHeight = poh->cy;
  765. pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  766. if ((DWORD) ppdev->cyScreen <= pvmList->dwHeight)
  767. {
  768. bCanFlip = TRUE;
  769. }
  770. }
  771. }
  772. // Capabilities supported:
  773. pHalInfo->ddCaps.dwFXCaps = 0;
  774. pHalInfo->ddCaps.dwCaps = DDCAPS_BLT
  775. | DDCAPS_BLTCOLORFILL
  776. | DDCAPS_COLORKEY;
  777. pHalInfo->ddCaps.dwCKeyCaps = DDCKEYCAPS_SRCBLT;
  778. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
  779. | DDSCAPS_PRIMARYSURFACE;
  780. if (bCanFlip)
  781. {
  782. pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
  783. }
  784. // Required alignments of the scan lines for each kind of memory:
  785. pHalInfo->vmiData.dwOffscreenAlign = 8 * ppdev->cBpp;
  786. // FourCCs supported:
  787. *pdwNumFourCC = 0;
  788. EXIT(DrvGetDirectDrawInfo);
  789. return(TRUE);
  790. }
  791. /******************************Public*Routine******************************\
  792. * BOOL DrvEnableDirectDraw
  793. *
  794. \**************************************************************************/
  795. BOOL DrvEnableDirectDraw(
  796. DHPDEV dhpdev,
  797. DD_CALLBACKS* pCallBacks,
  798. DD_SURFACECALLBACKS* pSurfaceCallBacks,
  799. DD_PALETTECALLBACKS* pPaletteCallBacks)
  800. {
  801. PDEV* ppdev;
  802. ENTER(DrvEnableDirectDraw);
  803. ppdev = (PDEV*) dhpdev;
  804. pCallBacks->WaitForVerticalBlank = DdWaitForVerticalBlank;
  805. pCallBacks->MapMemory = DdMapMemory;
  806. pCallBacks->dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK
  807. | DDHAL_CB32_MAPMEMORY;
  808. pSurfaceCallBacks->Blt = DdBlt;
  809. pSurfaceCallBacks->Flip = DdFlip;
  810. pSurfaceCallBacks->Lock = DdLock;
  811. pSurfaceCallBacks->Unlock = DdUnlock;
  812. pSurfaceCallBacks->GetBltStatus = DdGetBltStatus;
  813. pSurfaceCallBacks->GetFlipStatus = DdGetFlipStatus;
  814. pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_BLT
  815. | DDHAL_SURFCB32_FLIP
  816. | DDHAL_SURFCB32_LOCK
  817. | DDHAL_SURFCB32_UNLOCK
  818. | DDHAL_SURFCB32_GETBLTSTATUS
  819. | DDHAL_SURFCB32_GETFLIPSTATUS;
  820. // Note that we don't call 'vGetDisplayDuration' here, for a couple of
  821. // reasons:
  822. //
  823. // o Because the system is already running, it would be disconcerting
  824. // to pause the graphics for a good portion of a second just to read
  825. // the refresh rate;
  826. // o More importantly, we may not be in graphics mode right now.
  827. //
  828. // For both reasons, we always measure the refresh rate when we switch
  829. // to a new mode.
  830. EXIT(DrvEnableDirectDraw);
  831. return(TRUE);
  832. }
  833. /******************************Public*Routine******************************\
  834. * VOID DrvDisableDirectDraw
  835. *
  836. \**************************************************************************/
  837. VOID DrvDisableDirectDraw(
  838. DHPDEV dhpdev)
  839. {
  840. PDEV* ppdev;
  841. ENTER(DrvDisableDirectDraw);
  842. ppdev = (PDEV*) dhpdev;
  843. // DirectDraw is done with the display, so we can go back to using
  844. // all of off-screen memory ourselves:
  845. pohFree(ppdev, ppdev->pohDirectDraw);
  846. ppdev->pohDirectDraw = NULL;
  847. EXIT(DrvDisableDirectDraw);
  848. }
  849. /******************************Public*Routine******************************\
  850. * BOOL bAssertModeDirectDraw
  851. *
  852. \**************************************************************************/
  853. VOID vAssertModeDirectDraw(
  854. PDEV* ppdev,
  855. BOOL bEnabled)
  856. {
  857. }
  858. /******************************Public*Routine******************************\
  859. * BOOL bEnableDirectDraw
  860. *
  861. * This function is called when the mode is first initialized, right after
  862. * the miniport does the mode-set.
  863. *
  864. \**************************************************************************/
  865. BOOL bEnableDirectDraw(
  866. PDEV* ppdev)
  867. {
  868. ENTER(bEnableDirectDraw);
  869. // We're not going to bother to support accelerated DirectDraw on
  870. // the pre-ET6000 chips, because they don't have linear frame
  871. // buffers.
  872. if (ppdev->ulChipID == ET6000)
  873. {
  874. // Accurately measure the refresh rate for later:
  875. vGetDisplayDuration(ppdev);
  876. // DirectDraw is all set to be used on this card:
  877. ppdev->flStatus |= STAT_DIRECTDRAW;
  878. }
  879. EXIT(bEnableDirectDraw);
  880. return(TRUE);
  881. }
  882. /******************************Public*Routine******************************\
  883. * VOID vDisableDirectDraw
  884. *
  885. \**************************************************************************/
  886. VOID vDisableDirectDraw(
  887. PDEV* ppdev)
  888. {
  889. }