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.

1806 lines
59 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. // FourCC formats are encoded in reverse because we're little endian:
  10. #define FOURCC_YUY2 '2YUY'
  11. // Worst-case possible number of FIFO entries we'll have to wait for in
  12. // DdBlt for any operation:
  13. #define DDBLT_FIFO_COUNT 7
  14. // NT is kind enough to pre-calculate the 2-d surface offset as a 'hint' so
  15. // that we don't have to do the following, which would be 6 DIVs per blt:
  16. //
  17. // y += (offset / pitch)
  18. // x += (offset % pitch) / bytes_per_pixel
  19. #define convertToGlobalCord(x, y, surf) \
  20. { \
  21. y += surf->yHint; \
  22. x += surf->xHint; \
  23. }
  24. /******************************Public*Routine******************************\
  25. * VOID vYuvStretch
  26. *
  27. * Does an expanding stretch blt from a 16-bit YUV surface to video memory.
  28. *
  29. \**************************************************************************/
  30. VOID vYuvStretch(
  31. PDEV* ppdev,
  32. RECTL* prclDst,
  33. VOID* pvSrc,
  34. LONG lDeltaSrc,
  35. RECTL* prclSrc)
  36. {
  37. BYTE* pjBase;
  38. BYTE* pjDma;
  39. LONG cxMemory;
  40. LONG cxDst;
  41. LONG cxSrc;
  42. LONG cyDst;
  43. LONG cySrc;
  44. LONG cyWholeDuplicate;
  45. LONG lPartialDuplicate;
  46. LONG lError;
  47. LONG lErrorLimit;
  48. LONG xDstLeft;
  49. LONG xDstRight;
  50. LONG xDstRightFast;
  51. LONG yDstTop;
  52. LONG xSrcAlign;
  53. ULONG cd;
  54. BYTE* pjSrc;
  55. ULONG ulCmd;
  56. LONG lDstAddress;
  57. ULONG* pulSrc;
  58. ULONG* pulDma;
  59. ULONG i;
  60. LONG cyDuplicate;
  61. LONG cyBreak;
  62. LONG iBreak;
  63. pjBase = ppdev->pjBase;
  64. cxMemory = ppdev->cxMemory;
  65. pjDma = pjBase + DMAWND;
  66. ppdev->HopeFlags = SIGN_CACHE; // Only register that's zero when done
  67. cxDst = prclDst->right - prclDst->left;
  68. cxSrc = prclSrc->right - prclSrc->left;
  69. cyDst = prclDst->bottom - prclDst->top;
  70. cySrc = prclSrc->bottom - prclSrc->top;
  71. ASSERTDD((cySrc <= cyDst) && (cxSrc <= cxDst),
  72. "Expanding stretches only may be allowed here");
  73. // We'll be doing the vertical stretching in software, so calculate the
  74. // DDA terms here. We have the luxury of not worrying about overflow
  75. // because DirectDraw limits our coordinate space to 15 bits:
  76. cyWholeDuplicate = (cyDst / cySrc) - 1;
  77. lPartialDuplicate = (cyDst % cySrc);
  78. lErrorLimit = cySrc;
  79. lError = cySrc >> 1;
  80. xDstLeft = prclDst->left;
  81. xDstRight = prclDst->right - 1; // Note this is inclusive
  82. yDstTop = prclDst->top;
  83. cyDst = prclDst->bottom - prclDst->top;
  84. // Fast WRAM-WRAM blts have a funky requirement for 'FXRIGHT':
  85. switch (ppdev->cjPelSize)
  86. {
  87. case 1: xDstRightFast = xDstRight | 0x40; break;
  88. case 2: xDstRightFast = xDstRight | 0x20; break;
  89. case 4: xDstRightFast = xDstRight | 0x10; break;
  90. case 3: xDstRightFast = (((xDstRight * 3) + 2) | 0x40) / 3;
  91. break;
  92. }
  93. // Figure out how many scans we can duplicate before we hit the first
  94. // WRAM boundary:
  95. cyBreak = 0xffff;
  96. for (iBreak = 0; iBreak < ppdev->cyBreak; iBreak++)
  97. {
  98. if (ppdev->ayBreak[iBreak] >= yDstTop)
  99. {
  100. cyBreak = ppdev->ayBreak[iBreak] - yDstTop;
  101. break;
  102. }
  103. }
  104. CHECK_FIFO_SPACE(pjBase, 8);
  105. CP_WRITE(pjBase, DWG_YDST, yDstTop);
  106. CP_WRITE(pjBase, DWG_CXBNDRY, (xDstRight << bfxright_SHIFT)
  107. | (xDstLeft));
  108. // Make sure we always read dword-aligned from the source:
  109. xSrcAlign = prclSrc->left & 1;
  110. if (xSrcAlign)
  111. {
  112. xDstLeft -= cxDst / cxSrc; // We guess that Millennium takes ceiling
  113. }
  114. CP_WRITE(pjBase, DWG_FXBNDRY, (xDstRight << bfxright_SHIFT)
  115. | (xDstLeft & bfxleft_MASK));
  116. lDstAddress = (yDstTop - 1) * cxMemory + xDstLeft + ppdev->ulYDstOrg;
  117. CP_WRITE(pjBase, DWG_AR5, cxMemory);
  118. CP_WRITE(pjBase, DWG_AR3, lDstAddress);
  119. CP_WRITE(pjBase, DWG_AR0, lDstAddress + cxDst - 1);
  120. cd = (cxSrc + xSrcAlign + 1) >> 1;
  121. pjSrc = (BYTE*) pvSrc + (prclSrc->top * lDeltaSrc)
  122. + ((prclSrc->left - xSrcAlign) * 2);
  123. ASSERTDD(((ULONG_PTR) pjSrc & 3) == 0, "Must dword align source");
  124. if (cxDst >= 2 * cxSrc)
  125. {
  126. ulCmd = opcode_ILOAD_FILTER |
  127. atype_RPL |
  128. blockm_OFF |
  129. bltmod_BUYUV |
  130. pattern_OFF |
  131. transc_BG_OPAQUE |
  132. bop_SRCCOPY |
  133. shftzero_ZERO |
  134. sgnzero_ZERO;
  135. CP_WRITE(pjBase, DWG_AR2, 2 * cxSrc - 1);
  136. CP_WRITE(pjBase, DWG_AR6, 2 * cxSrc - cxDst - 1);
  137. }
  138. else
  139. {
  140. ulCmd = opcode_ILOAD_SCALE |
  141. atype_RPL |
  142. blockm_OFF |
  143. bltmod_BUYUV |
  144. pattern_OFF |
  145. transc_BG_OPAQUE |
  146. bop_SRCCOPY |
  147. shftzero_ZERO |
  148. sgnzero_ZERO;
  149. CP_WRITE(pjBase, DWG_AR2, cxSrc);
  150. CP_WRITE(pjBase, DWG_AR6, cxSrc - cxDst);
  151. }
  152. do {
  153. CHECK_FIFO_SPACE(pjBase, 2);
  154. CP_WRITE(pjBase, DWG_DWGCTL, ulCmd);
  155. CP_START(pjBase, DWG_LEN, 1);
  156. // Turn on pseudo-DMA so that we can use PCI burst mode:
  157. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  158. BLT_WRITE_ON(ppdev, pjBase);
  159. pulSrc = (ULONG*) pjSrc;
  160. pulDma = (ULONG*) pjDma;
  161. pjSrc += lDeltaSrc;
  162. #if defined(_X86_)
  163. __asm mov esi, pulSrc
  164. __asm mov edi, pulDma
  165. __asm mov ecx, cd
  166. __asm rep movsd
  167. #else
  168. for (i = cd; i != 0; i--)
  169. {
  170. WRITE_REGISTER_ULONG(pulDma, *pulSrc);
  171. pulSrc++;
  172. pulDma++;
  173. }
  174. #endif
  175. BLT_WRITE_OFF(ppdev, pjBase);
  176. // Do an iteration of the DDA to determine how many lines we'll
  177. // be duplicating. This biases
  178. cyDuplicate = cyWholeDuplicate;
  179. lError += lPartialDuplicate;
  180. if (lError >= lErrorLimit)
  181. {
  182. cyDuplicate++;
  183. lError -= lErrorLimit;
  184. }
  185. // Account for the line we just stretched:
  186. cyDst--;
  187. cyBreak--;
  188. // Remember not to duplicate past where we're supposed to end:
  189. if (cyDuplicate > cyDst)
  190. cyDuplicate = cyDst;
  191. if (cyDuplicate != 0)
  192. {
  193. cyDst -= cyDuplicate;
  194. cyBreak -= cyDuplicate;
  195. if (cyBreak >= 0)
  196. {
  197. // We haven't crossed a WRAM boundary, so we can use a
  198. // WRAM-WRAM blt to duplicate the scan:
  199. CHECK_FIFO_SPACE(pjBase, 4);
  200. CP_WRITE(pjBase, DWG_DWGCTL, opcode_FBITBLT |
  201. atype_RPL |
  202. blockm_OFF |
  203. bltmod_BFCOL |
  204. pattern_OFF |
  205. transc_BG_OPAQUE |
  206. bop_NOP |
  207. shftzero_ZERO |
  208. sgnzero_ZERO);
  209. CP_WRITE(pjBase, DWG_FXRIGHT, xDstRightFast);
  210. CP_START(pjBase, DWG_LEN, cyDuplicate);
  211. CP_WRITE(pjBase, DWG_FXRIGHT, xDstRight);
  212. }
  213. else
  214. {
  215. // We just crossed a WRAM boundary, so we have to use a
  216. // regular blt to duplicate the scan:
  217. CHECK_FIFO_SPACE(pjBase, 2);
  218. CP_WRITE(pjBase, DWG_DWGCTL, opcode_BITBLT |
  219. atype_RPL |
  220. blockm_OFF |
  221. bltmod_BFCOL |
  222. pattern_OFF |
  223. transc_BG_OPAQUE |
  224. bop_SRCCOPY |
  225. shftzero_ZERO |
  226. sgnzero_ZERO);
  227. CP_START(pjBase, DWG_LEN, cyDuplicate);
  228. iBreak++;
  229. if (iBreak >= ppdev->cyBreak)
  230. {
  231. // That was the last break we have to worry about:
  232. cyBreak = 0xffff;
  233. }
  234. else
  235. {
  236. cyBreak += ppdev->ayBreak[iBreak]
  237. - ppdev->ayBreak[iBreak - 1];
  238. }
  239. }
  240. }
  241. } while (cyDst != 0);
  242. // Reset the clipping, and we're done!
  243. CHECK_FIFO_SPACE(pjBase, 1);
  244. CP_WRITE(pjBase, DWG_CXBNDRY, (cxMemory - 1) << bcxright_SHIFT);
  245. }
  246. /******************************Public*Routine******************************\
  247. * VOID vYuvBlt
  248. *
  249. * Does a non-stretching blt from a 16-bit YUV surface to video memory.
  250. *
  251. \**************************************************************************/
  252. VOID vYuvBlt(
  253. PDEV* ppdev,
  254. RECTL* prclDst,
  255. VOID* pvSrc,
  256. LONG lDeltaSrc,
  257. POINTL* pptlSrc)
  258. {
  259. BYTE* pjBase;
  260. BYTE* pjDma;
  261. LONG cy;
  262. LONG xLeft;
  263. LONG xRight;
  264. LONG xAlign;
  265. ULONG cd;
  266. BYTE* pjSrc;
  267. ULONG* pulSrc;
  268. ULONG* pulDma;
  269. ULONG i;
  270. pjBase = ppdev->pjBase;
  271. pjDma = pjBase + DMAWND;
  272. ppdev->HopeFlags = SIGN_CACHE; // Only register that's zero when done
  273. CHECK_FIFO_SPACE(pjBase, 6);
  274. CP_WRITE(pjBase, DWG_DWGCTL, opcode_ILOAD
  275. | atype_RPL
  276. | blockm_OFF
  277. | pattern_OFF
  278. | transc_BG_OPAQUE
  279. | bop_SRCCOPY
  280. | shftzero_ZERO
  281. | sgnzero_ZERO
  282. | bltmod_BUYUV);
  283. xLeft = prclDst->left;
  284. xRight = prclDst->right;
  285. cy = prclDst->bottom - prclDst->top;
  286. CP_WRITE(pjBase, DWG_AR3, 0);
  287. CP_WRITE(pjBase, DWG_YDSTLEN, (prclDst->top << yval_SHIFT) | cy);
  288. // Make sure we always read dword-aligned from the source:
  289. xAlign = pptlSrc->x & 1;
  290. if (xAlign)
  291. {
  292. CP_WRITE(pjBase, DWG_CXLEFT, xLeft);
  293. xLeft--;
  294. }
  295. CP_WRITE(pjBase, DWG_FXBNDRY, ((xRight - 1) << bfxright_SHIFT) |
  296. (xLeft & bfxleft_MASK));
  297. CP_START(pjBase, DWG_AR0, xRight - xLeft - 1);
  298. cd = (xRight - xLeft + 1) >> 1;
  299. pjSrc = (BYTE*) pvSrc + (pptlSrc->y * lDeltaSrc)
  300. + ((pptlSrc->x - xAlign) * 2);
  301. ASSERTDD(((ULONG_PTR) pjSrc & 3) == 0, "Must dword align source");
  302. // Turn on pseudo-DMA so that we can use PCI burst mode:
  303. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  304. BLT_WRITE_ON(ppdev, pjBase);
  305. do {
  306. pulSrc = (ULONG*) pjSrc;
  307. pulDma = (ULONG*) pjDma;
  308. pjSrc += lDeltaSrc;
  309. #if defined(_X86_)
  310. __asm mov esi, pulSrc
  311. __asm mov edi, pulDma
  312. __asm mov ecx, cd
  313. __asm rep movsd
  314. #else
  315. for (i = cd; i != 0; i--)
  316. {
  317. WRITE_REGISTER_ULONG(pulDma, *pulSrc);
  318. pulSrc++;
  319. pulDma++;
  320. }
  321. #endif
  322. } while (--cy != 0);
  323. // Reset the registers and leave:
  324. BLT_WRITE_OFF(ppdev, pjBase);
  325. if (xAlign)
  326. {
  327. CHECK_FIFO_SPACE(pjBase, 1);
  328. CP_WRITE(pjBase, DWG_CXLEFT, 0);
  329. }
  330. }
  331. /******************************Public*Routine******************************\
  332. * VOID vGetDisplayDuration
  333. *
  334. * Get the length, in EngQueryPerformanceCounter() ticks, of a refresh cycle.
  335. *
  336. * If we could trust the miniport to return back and accurate value for
  337. * the refresh rate, we could use that. Unfortunately, our miniport doesn't
  338. * ensure that it's an accurate value.
  339. *
  340. \**************************************************************************/
  341. #define NUM_VBLANKS_TO_MEASURE 1
  342. #define NUM_MEASUREMENTS_TO_TAKE 8
  343. VOID vGetDisplayDuration(PDEV* ppdev)
  344. {
  345. BYTE* pjBase = ppdev->pjBase;
  346. LONG i;
  347. LONG j;
  348. LONGLONG li;
  349. LONGLONG liMin;
  350. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  351. memset(&ppdev->flipRecord, 0, sizeof(ppdev->flipRecord));
  352. // Warm up EngQUeryPerformanceCounter to make sure it's in the working
  353. // set:
  354. EngQueryPerformanceCounter(&li);
  355. // Unfortunately, since NT is a proper multitasking system, we can't
  356. // just disable interrupts to take an accurate reading. We also can't
  357. // do anything so goofy as dynamically change our thread's priority to
  358. // real-time.
  359. //
  360. // So we just do a bunch of short measurements and take the minimum.
  361. //
  362. // It would be 'okay' if we got a result that's longer than the actual
  363. // VBlank cycle time -- nothing bad would happen except that the app
  364. // would run a little slower. We don't want to get a result that's
  365. // shorter than the actual VBlank cycle time -- that could cause us
  366. // to start drawing over a frame before the Flip has occured.
  367. while (VBLANK_IS_ACTIVE(pjBase))
  368. ;
  369. while (!(VBLANK_IS_ACTIVE(pjBase)))
  370. ;
  371. for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++)
  372. {
  373. // We're at the start of the VBlank active cycle!
  374. EngQueryPerformanceCounter(&aliMeasurement[i]);
  375. // Okay, so life in a multi-tasking environment isn't all that
  376. // simple. What if we had taken a context switch just before
  377. // the above EngQueryPerformanceCounter call, and now were half
  378. // way through the VBlank inactive cycle? Then we would measure
  379. // only half a VBlank cycle, which is obviously bad. The worst
  380. // thing we can do is get a time shorter than the actual VBlank
  381. // cycle time.
  382. //
  383. // So we solve this by making sure we're in the VBlank active
  384. // time before and after we query the time. If it's not, we'll
  385. // sync up to the next VBlank (it's okay to measure this period --
  386. // it will be guaranteed to be longer than the VBlank cycle and
  387. // will likely be thrown out when we select the minimum sample).
  388. // There's a chance that we'll take a context switch and return
  389. // just before the end of the active VBlank time -- meaning that
  390. // the actual measured time would be less than the true amount --
  391. // but since the VBlank is active less than 1% of the time, this
  392. // means that we would have a maximum of 1% error approximately
  393. // 1% of the times we take a context switch. An acceptable risk.
  394. //
  395. // This next line will cause us wait if we're no longer in the
  396. // VBlank active cycle as we should be at this point:
  397. while (!(VBLANK_IS_ACTIVE(pjBase)))
  398. ;
  399. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  400. {
  401. while (VBLANK_IS_ACTIVE(pjBase))
  402. ;
  403. while (!(VBLANK_IS_ACTIVE(pjBase)))
  404. ;
  405. }
  406. }
  407. EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
  408. // Use the minimum:
  409. liMin = aliMeasurement[1] - aliMeasurement[0];
  410. DISPDBG((1, "Refresh count: %li - %li", 1, (ULONG) liMin));
  411. for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
  412. {
  413. li = aliMeasurement[i] - aliMeasurement[i - 1];
  414. DISPDBG((1, " %li - %li", i, (ULONG) li));
  415. if (li < liMin)
  416. liMin = li;
  417. }
  418. // Round the result:
  419. ppdev->flipRecord.liFlipDuration
  420. = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
  421. DISPDBG((1, "Frequency %li.%03li Hz",
  422. (ULONG) (EngQueryPerformanceFrequency(&li),
  423. li / ppdev->flipRecord.liFlipDuration),
  424. (ULONG) (EngQueryPerformanceFrequency(&li),
  425. ((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
  426. ppdev->flipRecord.bFlipFlag = FALSE;
  427. ppdev->flipRecord.fpFlipFrom = 0;
  428. }
  429. /******************************Public*Routine******************************\
  430. * HRESULT ddrvalUpdateFlipStatus
  431. *
  432. * Checks to if the most recent flip has occurred.
  433. *
  434. * Takes advantage of the hardware's ability to get the current scan line
  435. * to determine if a vertical retrace has occured since the flip command
  436. * was given.
  437. *
  438. \**************************************************************************/
  439. HRESULT ddrvalUpdateFlipStatus(
  440. PDEV* ppdev,
  441. FLATPTR fpVidMem) // Surface for which we're requesting flip status;
  442. // -1 indicates status of last flip, regardless of what
  443. // surface it was.
  444. {
  445. BYTE* pjBase;
  446. DWORD dwScanLine;
  447. LONGLONG liTime;
  448. pjBase = ppdev->pjBase;
  449. if (ppdev->flipRecord.bFlipFlag)
  450. {
  451. dwScanLine = GET_SCANLINE(pjBase);
  452. if (dwScanLine < ppdev->flipRecord.dwScanLine)
  453. {
  454. ppdev->flipRecord.bFlipFlag = FALSE;
  455. }
  456. else
  457. {
  458. ppdev->flipRecord.dwScanLine = dwScanLine;
  459. if ((fpVidMem == (FLATPTR) -1) ||
  460. (fpVidMem == ppdev->flipRecord.fpFlipFrom))
  461. {
  462. // Sampling the current scan line at random times is not a
  463. // fool-proof indicator that the flip has occured. As a
  464. // backup, if the time elapsed since the flip command was
  465. // given is more than the duration of one entire refresh of
  466. // the display, then we know for sure it has happened:
  467. EngQueryPerformanceCounter(&liTime);
  468. if (liTime - ppdev->flipRecord.liFlipTime
  469. <= ppdev->flipRecord.liFlipDuration)
  470. {
  471. return(DDERR_WASSTILLDRAWING);
  472. }
  473. ppdev->flipRecord.bFlipFlag = FALSE;
  474. }
  475. }
  476. }
  477. return(DD_OK);
  478. }
  479. /******************************Public*Routine******************************\
  480. * DWORD DdBlt
  481. *
  482. \**************************************************************************/
  483. DWORD DdBlt(
  484. PDD_BLTDATA lpBlt)
  485. {
  486. PDD_SURFACE_GLOBAL srcSurf;
  487. PDD_SURFACE_LOCAL dstSurfx;
  488. PDD_SURFACE_GLOBAL dstSurf;
  489. PDEV* ppdev;
  490. HRESULT ddRVal;
  491. DWORD dstX;
  492. DWORD dstY;
  493. DWORD dwFlags;
  494. DWORD srcX;
  495. DWORD srcY;
  496. LONG dstWidth;
  497. LONG dstHeight;
  498. LONG srcWidth;
  499. LONG srcHeight;
  500. ULONG ulBltCmd;
  501. LONG lSrcStart;
  502. LONG lSignedPitch;
  503. RECTL rclSrc;
  504. RECTL rclDest;
  505. BYTE* pjBase;
  506. ppdev = (PDEV*) lpBlt->lpDD->dhpdev;
  507. pjBase = ppdev->pjBase;
  508. dstSurfx = lpBlt->lpDDDestSurface;
  509. dstSurf = dstSurfx->lpGbl;
  510. ASSERTDD(dstSurf->ddpfSurface.dwSize == sizeof(DDPIXELFORMAT),
  511. "NT is supposed to guarantee that ddpfSurface.dwSize is valid");
  512. // We don't have to do any drawing to YUV surfaces. Note that unlike
  513. // Windows 95, Windows NT always guarantees that there will be a valid
  514. // 'ddpfSurface' structure, so we don't have to first check if
  515. // 'dwSize == sizeof(DDPIXELFORMAT)':
  516. if (dstSurf->ddpfSurface.dwFlags & DDPF_FOURCC)
  517. {
  518. return(DDHAL_DRIVER_NOTHANDLED);
  519. }
  520. // Is a flip in progress?
  521. ddRVal = ddrvalUpdateFlipStatus(ppdev, dstSurf->fpVidMem);
  522. if (ddRVal != DD_OK)
  523. {
  524. lpBlt->ddRVal = ddRVal;
  525. return(DDHAL_DRIVER_HANDLED);
  526. }
  527. dwFlags = lpBlt->dwFlags;
  528. if (dwFlags & DDBLT_ASYNC)
  529. {
  530. // If async, then only work if we won't have to wait on the
  531. // accelerator to start the command.
  532. //
  533. // The FIFO wait should account for the worst-case possible
  534. // blt that we would do:
  535. //
  536. // We should check for enough entries that we're guaranteed
  537. // to not have to wait later in this routine.
  538. if (GET_FIFO_SPACE(pjBase) < DDBLT_FIFO_COUNT)
  539. {
  540. lpBlt->ddRVal = DDERR_WASSTILLDRAWING;
  541. return(DDHAL_DRIVER_HANDLED);
  542. }
  543. }
  544. // Copy destination rectangle:
  545. dstX = lpBlt->rDest.left;
  546. dstY = lpBlt->rDest.top;
  547. dstWidth = lpBlt->rDest.right - lpBlt->rDest.left;
  548. dstHeight = lpBlt->rDest.bottom - lpBlt->rDest.top;
  549. convertToGlobalCord(dstX, dstY, dstSurf);
  550. if (dwFlags & DDBLT_COLORFILL)
  551. {
  552. ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE | PATTERN_CACHE);
  553. if (ppdev->iBitmapFormat == BMF_24BPP)
  554. {
  555. // We can't use block mode.
  556. ulBltCmd = (opcode_TRAP + blockm_OFF + atype_RPL + solid_SOLID +
  557. arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
  558. bop_SRCCOPY + pattern_OFF + transc_BG_OPAQUE);
  559. }
  560. else
  561. {
  562. ulBltCmd = (opcode_TRAP + blockm_ON + solid_SOLID +
  563. arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
  564. bop_SRCCOPY + pattern_OFF + transc_BG_OPAQUE);
  565. }
  566. CHECK_FIFO_SPACE(pjBase, 4);
  567. CP_WRITE(pjBase, DWG_DWGCTL, ulBltCmd);
  568. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, lpBlt->bltFX.dwFillColor));
  569. CP_WRITE(pjBase, DWG_FXBNDRY, (((dstX + dstWidth) << bfxright_SHIFT) | dstX));
  570. CP_START(pjBase, DWG_YDSTLEN, (((dstY) << yval_SHIFT) | dstHeight));
  571. lpBlt->ddRVal = DD_OK;
  572. return(DDHAL_DRIVER_HANDLED);
  573. }
  574. // We specified with Our ddCaps.dwCaps that we handle a limited number
  575. // of commands, and by this point in our routine we've handled everything
  576. // except DDBLT_ROP. DirectDraw and GDI shouldn't pass us anything
  577. // else; we'll assert on debug builds to prove this:
  578. ASSERTDD((dwFlags & DDBLT_ROP) && (lpBlt->lpDDSrcSurface),
  579. "Expected dwFlags commands of only DDBLT_ASYNC and DDBLT_COLORFILL");
  580. // Get source rectangle dimensions:
  581. srcSurf = lpBlt->lpDDSrcSurface->lpGbl;
  582. srcX = lpBlt->rSrc.left;
  583. srcY = lpBlt->rSrc.top;
  584. srcWidth = lpBlt->rSrc.right - lpBlt->rSrc.left;
  585. srcHeight = lpBlt->rSrc.bottom - lpBlt->rSrc.top;
  586. rclDest.left = dstX;
  587. rclDest.right = dstX + dstWidth;
  588. rclDest.top = dstY;
  589. rclDest.bottom = dstY + dstHeight;
  590. if (srcSurf->ddpfSurface.dwFlags & DDPF_FOURCC)
  591. {
  592. rclSrc.left = srcX;
  593. rclSrc.top = srcY;
  594. rclSrc.right = srcX + srcWidth;
  595. rclSrc.bottom = srcY + srcHeight;
  596. if ((dstWidth == srcWidth) && (dstHeight == srcHeight))
  597. {
  598. vYuvBlt(ppdev,
  599. &rclDest,
  600. (VOID*) srcSurf->fpVidMem,
  601. srcSurf->lPitch,
  602. (POINTL*) &rclSrc);
  603. }
  604. // Note that we would fall over if we actually got a shrink here,
  605. // even though we've set our caps to indicate we can only do
  606. // expands. We're paranoid and don't want to ever fall over:
  607. else if ((dstWidth >= srcWidth) && (dstHeight >= srcHeight))
  608. {
  609. vYuvStretch(ppdev,
  610. &rclDest,
  611. (VOID*) srcSurf->fpVidMem,
  612. srcSurf->lPitch,
  613. &rclSrc);
  614. }
  615. lpBlt->ddRVal = DD_OK;
  616. return(DDHAL_DRIVER_HANDLED);
  617. }
  618. // NT only ever gives us SRCCOPY rops, so don't even bother checking
  619. // for anything else.
  620. convertToGlobalCord(srcX, srcY, srcSurf);
  621. rclSrc.left = srcX;
  622. rclSrc.top = srcY;
  623. rclSrc.right = srcX + srcWidth;
  624. rclSrc.bottom = srcY + srcHeight;
  625. // Must be set for our copy routines to operate properly:
  626. ppdev->xOffset = 0;
  627. ppdev->yOffset = 0;
  628. if ((srcWidth == dstWidth) && (srcHeight == dstHeight))
  629. {
  630. // There's no stretching involved, so do a straight screen-to-
  631. // screen copy. 'vMilCopyBlt' takes care of the overlapping
  632. // cases, and
  633. vMilCopyBlt(ppdev, 1, &rclDest, 0xcccc, (POINTL*) &rclSrc, &rclDest);
  634. }
  635. else
  636. {
  637. // Ugh, we've been asked to stretch an off-screen surface. We'll
  638. // just pass it to our hardware-assisted StretchBlt routine.
  639. //
  640. // Unfortunately, the source is in off-screen memory and so the
  641. // performance will be terrible -- slower than if the surface had
  642. // been created in system memory. We have to support stretched RGB
  643. // surfaces in the first place because we set DDCAPS_BLTSTRETCH so
  644. // that we could use the Millennium's YUV stretch capabilities --
  645. // and DirectDraw has no concept of being able to say "we support
  646. // hardware stretches with these types of off-screen surfaces, but
  647. // not those with those other types of off-screen surfaces." Oh
  648. // well. I expect that if applications will be doing stretches,
  649. // they'll be doing it mostly from YUV surfaces (as will be the
  650. // case with ActiveMovie), so this should be a win overall.
  651. //
  652. // Note: If you are modeling your driver on this code and don't have
  653. // any hardware stretch capabilities, then simply don't set
  654. // DDCAPS_BLTSTRETCH, and you'll never have to worry about
  655. // this! We only do this weirdness here because the
  656. // Millennium can hardware stretch YUV surfaces but not RGB
  657. // surfaces. (Sort of.)
  658. vStretchDIB(ppdev,
  659. &rclDest,
  660. ppdev->pjScreen + (ppdev->ulYDstOrg * ppdev->cjPelSize),
  661. ppdev->lDelta,
  662. &rclSrc,
  663. &rclDest);
  664. }
  665. lpBlt->ddRVal = DD_OK;
  666. return(DDHAL_DRIVER_HANDLED);
  667. }
  668. /******************************Public*Routine******************************\
  669. * DWORD DdFlip
  670. *
  671. \**************************************************************************/
  672. DWORD DdFlip(
  673. PDD_FLIPDATA lpFlip)
  674. {
  675. PDEV* ppdev;
  676. BYTE* pjBase;
  677. HRESULT ddRVal;
  678. ULONG ulMemoryOffset;
  679. ULONG ulLowOffset;
  680. ULONG ulMiddleOffset;
  681. ULONG ulHighOffset;
  682. BYTE jReg;
  683. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  684. pjBase = ppdev->pjBase;
  685. // Is the current flip still in progress?
  686. //
  687. // Don't want a flip to work until after the last flip is done,
  688. // so we ask for the general flip status and ignore the vmem.
  689. ddRVal = ddrvalUpdateFlipStatus(ppdev, (FLATPTR) -1);
  690. if ((ddRVal != DD_OK) || (IS_BUSY(pjBase)))
  691. {
  692. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  693. return(DDHAL_DRIVER_HANDLED);
  694. }
  695. // Do the flip:
  696. ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem >> 2);
  697. ulMemoryOffset >>= ((ppdev->flFeatures & INTERLEAVE_MODE) ? 1 : 0);
  698. ulLowOffset = 0x0d | ((ulMemoryOffset & 0x0000ff) << 8);
  699. ulMiddleOffset = 0x0c | ((ulMemoryOffset & 0x00ff00));
  700. ulHighOffset = 0x00 | ((ulMemoryOffset & 0x0f0000) >> 8);
  701. // Make sure that the border/blanking period isn't active; wait if
  702. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  703. // that will increase the odds that we can't flip the next time:
  704. while (!(DISPLAY_IS_ACTIVE(pjBase)))
  705. ;
  706. CP_WRITE_REGISTER_BYTE(pjBase + VGA_CRTCEXT_INDEX, 0x00);
  707. jReg = CP_READ_REGISTER_BYTE(pjBase + VGA_CRTCEXT_DATA);
  708. jReg &= ~0x0f;
  709. CP_WRITE_REGISTER_WORD(pjBase + VGA_CRTC_INDEX, ulLowOffset);
  710. CP_WRITE_REGISTER_WORD(pjBase + VGA_CRTC_INDEX, ulMiddleOffset);
  711. CP_WRITE_REGISTER_WORD(pjBase + VGA_CRTCEXT_INDEX, ((ulHighOffset) |
  712. (jReg << 8)));
  713. // Remember where and when we were when we did the flip:
  714. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  715. ppdev->flipRecord.dwScanLine = GET_SCANLINE(pjBase);
  716. ppdev->flipRecord.bFlipFlag = TRUE;
  717. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  718. lpFlip->ddRVal = DD_OK;
  719. return(DDHAL_DRIVER_HANDLED);
  720. }
  721. /******************************Public*Routine******************************\
  722. * DWORD DdLock
  723. *
  724. \**************************************************************************/
  725. DWORD DdLock(
  726. PDD_LOCKDATA lpLock)
  727. {
  728. PDEV* ppdev;
  729. BYTE* pjBase;
  730. DD_SURFACE_GLOBAL* lpSurface;
  731. HRESULT ddRVal;
  732. ppdev = (PDEV*) lpLock->lpDD->dhpdev;
  733. pjBase = ppdev->pjBase;
  734. lpSurface = lpLock->lpDDSurface->lpGbl;
  735. if (lpSurface->ddpfSurface.dwFlags & DDPF_FOURCC)
  736. {
  737. // We create all FourCC surfaces in system memory, so just return
  738. // the user-mode address:
  739. lpLock->lpSurfData = (VOID*) lpSurface->fpVidMem;
  740. lpLock->ddRVal = DD_OK;
  741. // When a driver returns DD_OK and DDHAL_DRIVER_HANDLED from DdLock,
  742. // DirectDraw expects it to have adjusted the resulting pointer
  743. // to point to the upper left corner of the specified rectangle, if
  744. // any:
  745. if (lpLock->bHasRect)
  746. {
  747. lpLock->lpSurfData = (VOID*) ((BYTE*) lpLock->lpSurfData
  748. + lpLock->rArea.top * lpSurface->lPitch
  749. + lpLock->rArea.left
  750. * (lpSurface->ddpfSurface.dwYUVBitCount >> 3));
  751. }
  752. return(DDHAL_DRIVER_HANDLED);
  753. }
  754. // Check to see if any pending physical flip has occurred.
  755. // Don't allow a lock if a blt is in progress:
  756. ddRVal = ddrvalUpdateFlipStatus(ppdev, lpSurface->fpVidMem);
  757. if (ddRVal != DD_OK)
  758. {
  759. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  760. return(DDHAL_DRIVER_HANDLED);
  761. }
  762. // Here's one of the places where the Windows 95 and Windows NT DirectDraw
  763. // implementations differ: on Windows NT, you should watch for
  764. // DDLOCK_WAIT and loop in the driver while the accelerator is busy.
  765. // On Windows 95, it doesn't really matter.
  766. //
  767. // (The reason is that Windows NT allows applications to draw directly
  768. // to the frame buffer even while the accelerator is running, and does
  769. // not synchronize everything on the Win16Lock. Note that on Windows NT,
  770. // it is even possible for multiple threads to be holding different
  771. // DirectDraw surface locks at the same time.)
  772. if (lpLock->dwFlags & DDLOCK_WAIT)
  773. {
  774. WAIT_NOT_BUSY(pjBase)
  775. }
  776. else if (IS_BUSY(pjBase))
  777. {
  778. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  779. return(DDHAL_DRIVER_HANDLED);
  780. }
  781. // Because we correctly set 'fpVidMem' to be the offset into our frame
  782. // buffer when we created the surface, DirectDraw will automatically take
  783. // care of adding in the user-mode frame buffer address if we return
  784. // DDHAL_DRIVER_NOTHANDLED:
  785. return(DDHAL_DRIVER_NOTHANDLED);
  786. }
  787. /******************************Public*Routine******************************\
  788. * DWORD DdGetBltStatus
  789. *
  790. * Doesn't currently really care what surface is specified, just checks
  791. * and goes.
  792. *
  793. \**************************************************************************/
  794. DWORD DdGetBltStatus(
  795. PDD_GETBLTSTATUSDATA lpGetBltStatus)
  796. {
  797. PDEV* ppdev;
  798. HRESULT ddRVal;
  799. BYTE* pjBase;
  800. ppdev = (PDEV*) lpGetBltStatus->lpDD->dhpdev;
  801. pjBase = ppdev->pjBase;
  802. ddRVal = DD_OK;
  803. if (lpGetBltStatus->dwFlags == DDGBS_CANBLT)
  804. {
  805. // DDGBS_CANBLT case: can we add a blt?
  806. ddRVal = ddrvalUpdateFlipStatus(ppdev,
  807. lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
  808. if (ddRVal == DD_OK)
  809. {
  810. // There was no flip going on, so is there room in the FIFO
  811. // to add a blt?
  812. if (GET_FIFO_SPACE(pjBase) < DDBLT_FIFO_COUNT)
  813. {
  814. ddRVal = DDERR_WASSTILLDRAWING;
  815. }
  816. }
  817. }
  818. else
  819. {
  820. // DDGBS_ISBLTDONE case: is a blt in progress?
  821. if (IS_BUSY(pjBase))
  822. {
  823. ddRVal = DDERR_WASSTILLDRAWING;
  824. }
  825. }
  826. lpGetBltStatus->ddRVal = ddRVal;
  827. return(DDHAL_DRIVER_HANDLED);
  828. }
  829. /******************************Public*Routine******************************\
  830. * DWORD DdMapMemory
  831. *
  832. * This is a new DDI call specific to Windows NT that is used to map
  833. * or unmap all the application modifiable portions of the frame buffer
  834. * into the specified process's address space.
  835. *
  836. \**************************************************************************/
  837. DWORD DdMapMemory(
  838. PDD_MAPMEMORYDATA lpMapMemory)
  839. {
  840. PDEV* ppdev;
  841. VIDEO_SHARE_MEMORY ShareMemory;
  842. VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation;
  843. DWORD ReturnedDataLength;
  844. ppdev = (PDEV*) lpMapMemory->lpDD->dhpdev;
  845. if (lpMapMemory->bMap)
  846. {
  847. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  848. // 'RequestedVirtualAddress' isn't actually used for the SHARE IOCTL:
  849. ShareMemory.RequestedVirtualAddress = 0;
  850. // We map in starting at the top of the frame buffer:
  851. ShareMemory.ViewOffset = 0;
  852. // We map down to the end of the frame buffer.
  853. //
  854. // Note: There is a 64k granularity on the mapping (meaning that
  855. // we have to round up to 64k).
  856. //
  857. // Note: If there is any portion of the frame buffer that must
  858. // not be modified by an application, that portion of memory
  859. // MUST NOT be mapped in by this call. This would include
  860. // any data that, if modified by a malicious application,
  861. // would cause the driver to crash. This could include, for
  862. // example, any DSP code that is kept in off-screen memory.
  863. ShareMemory.ViewSize
  864. = ROUND_UP_TO_64K(ppdev->cyMemory * ppdev->lDelta);
  865. if (EngDeviceIoControl(ppdev->hDriver,
  866. IOCTL_VIDEO_SHARE_VIDEO_MEMORY,
  867. &ShareMemory,
  868. sizeof(VIDEO_SHARE_MEMORY),
  869. &ShareMemoryInformation,
  870. sizeof(VIDEO_SHARE_MEMORY_INFORMATION),
  871. &ReturnedDataLength))
  872. {
  873. DISPDBG((0, "Failed IOCTL_VIDEO_SHARE_MEMORY"));
  874. lpMapMemory->ddRVal = DDERR_GENERIC;
  875. return(DDHAL_DRIVER_HANDLED);
  876. }
  877. lpMapMemory->fpProcess = (FLATPTR)ShareMemoryInformation.VirtualAddress;
  878. }
  879. else
  880. {
  881. ShareMemory.ProcessHandle = lpMapMemory->hProcess;
  882. ShareMemory.ViewOffset = 0;
  883. ShareMemory.ViewSize = 0;
  884. ShareMemory.RequestedVirtualAddress = (VOID*) lpMapMemory->fpProcess;
  885. if (EngDeviceIoControl(ppdev->hDriver,
  886. IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY,
  887. &ShareMemory,
  888. sizeof(VIDEO_SHARE_MEMORY),
  889. NULL,
  890. 0,
  891. &ReturnedDataLength))
  892. {
  893. RIP("Failed IOCTL_VIDEO_UNSHARE_MEMORY");
  894. }
  895. }
  896. lpMapMemory->ddRVal = DD_OK;
  897. return(DDHAL_DRIVER_HANDLED);
  898. }
  899. /******************************Public*Routine******************************\
  900. * DWORD DdGetFlipStatus
  901. *
  902. * If the display has gone through one refresh cycle since the flip
  903. * occurred, we return DD_OK. If it has not gone through one refresh
  904. * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
  905. * is still busy "drawing" the flipped page. We also return
  906. * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted
  907. * to know if they could flip yet.
  908. *
  909. \**************************************************************************/
  910. DWORD DdGetFlipStatus(
  911. PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  912. {
  913. PDEV* ppdev;
  914. BYTE* pjBase;
  915. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  916. pjBase = ppdev->pjBase;
  917. // We don't want a flip to work until after the last flip is done,
  918. // so we ask for the general flip status and ignore the vmem:
  919. lpGetFlipStatus->ddRVal = ddrvalUpdateFlipStatus(ppdev, (FLATPTR) -1);
  920. // Check if the bltter is busy if someone wants to know if they can
  921. // flip:
  922. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  923. {
  924. if ((lpGetFlipStatus->ddRVal == DD_OK) && (IS_BUSY(pjBase)))
  925. {
  926. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  927. }
  928. }
  929. return(DDHAL_DRIVER_HANDLED);
  930. }
  931. /******************************Public*Routine******************************\
  932. * DWORD DdWaitForVerticalBlank
  933. *
  934. \**************************************************************************/
  935. DWORD DdWaitForVerticalBlank(
  936. PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  937. {
  938. PDEV* ppdev;
  939. BYTE* pjBase;
  940. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  941. pjBase = ppdev->pjBase;
  942. switch (lpWaitForVerticalBlank->dwFlags)
  943. {
  944. case DDWAITVB_I_TESTVB:
  945. // If TESTVB, it's just a request for the current vertical blank
  946. // status:
  947. if (VBLANK_IS_ACTIVE(pjBase))
  948. {
  949. lpWaitForVerticalBlank->bIsInVB = TRUE;
  950. }
  951. else
  952. {
  953. lpWaitForVerticalBlank->bIsInVB = FALSE;
  954. }
  955. lpWaitForVerticalBlank->ddRVal = DD_OK;
  956. return(DDHAL_DRIVER_HANDLED);
  957. case DDWAITVB_BLOCKBEGIN:
  958. // If BLOCKBEGIN is requested, we wait until the vertical blank
  959. // is over, and then wait for the display period to end:
  960. while (VBLANK_IS_ACTIVE(pjBase))
  961. ;
  962. while (!(VBLANK_IS_ACTIVE(pjBase)))
  963. ;
  964. lpWaitForVerticalBlank->ddRVal = DD_OK;
  965. return(DDHAL_DRIVER_HANDLED);
  966. case DDWAITVB_BLOCKEND:
  967. // If BLOCKEND is requested, we wait for the vblank interval to end:
  968. while (!(VBLANK_IS_ACTIVE(pjBase)))
  969. ;
  970. while (VBLANK_IS_ACTIVE(pjBase))
  971. ;
  972. lpWaitForVerticalBlank->ddRVal = DD_OK;
  973. return(DDHAL_DRIVER_HANDLED);
  974. }
  975. return(DDHAL_DRIVER_NOTHANDLED);
  976. }
  977. /******************************Public*Routine******************************\
  978. * DWORD DdGetScanLine
  979. *
  980. * Reads the scan line currently being scanned by the CRT.
  981. *
  982. \**************************************************************************/
  983. DWORD DdGetScanLine(
  984. PDD_GETSCANLINEDATA lpGetScanLine)
  985. {
  986. PDEV* ppdev;
  987. BYTE* pjBase;
  988. ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
  989. pjBase = ppdev->pjBase;
  990. lpGetScanLine->dwScanLine = GET_SCANLINE(pjBase);
  991. lpGetScanLine->ddRVal = DD_OK;
  992. return(DDHAL_DRIVER_HANDLED);
  993. }
  994. /******************************Public*Routine******************************\
  995. * DWORD DdCanCreateSurface
  996. *
  997. * Called by DirectDraw to determine if the driver can create a particular
  998. * off-screen surface type.
  999. *
  1000. \**************************************************************************/
  1001. DWORD DdCanCreateSurface(
  1002. PDD_CANCREATESURFACEDATA lpCanCreateSurface)
  1003. {
  1004. PDEV* ppdev;
  1005. LPDDSURFACEDESC lpSurfaceDesc;
  1006. ppdev = (PDEV*) lpCanCreateSurface->lpDD->dhpdev;
  1007. lpSurfaceDesc = lpCanCreateSurface->lpDDSurfaceDesc;
  1008. // It's trivially easy to create surfaces that are the same type as
  1009. // the primary surface:
  1010. if (!lpCanCreateSurface->bIsDifferentPixelFormat)
  1011. {
  1012. lpCanCreateSurface->ddRVal = DD_OK;
  1013. return(DDHAL_DRIVER_HANDLED);
  1014. }
  1015. // The only type of YUV mode that the Millennium supports is
  1016. // "YUY2". The Millennium also supports 24bpp and 32bpp surfaces,
  1017. // but we won't support them because they're not used very much
  1018. // and there isn't any good testing coverage for it.
  1019. //
  1020. // In addition, the Millennium supports YUV only when in RGB modes,
  1021. // and at 8bpp we're always running palettized.
  1022. if ((lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_FOURCC) &&
  1023. (lpSurfaceDesc->ddpfPixelFormat.dwFourCC == FOURCC_YUY2) &&
  1024. ((ppdev->iBitmapFormat == BMF_16BPP) ||
  1025. (ppdev->iBitmapFormat == BMF_32BPP)))
  1026. {
  1027. // We have to fill-in the bit count:
  1028. lpSurfaceDesc->ddpfPixelFormat.dwYUVBitCount = 16;
  1029. lpCanCreateSurface->ddRVal = DD_OK;
  1030. return(DDHAL_DRIVER_HANDLED);
  1031. }
  1032. if (lpSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB)
  1033. {
  1034. DISPDBG((0, "Failed creation of %libpp RGB surface %lx %lx %lx",
  1035. lpSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
  1036. lpSurfaceDesc->ddpfPixelFormat.dwRBitMask,
  1037. lpSurfaceDesc->ddpfPixelFormat.dwGBitMask,
  1038. lpSurfaceDesc->ddpfPixelFormat.dwBBitMask));
  1039. }
  1040. else
  1041. {
  1042. DISPDBG((0, "Failed creation of type 0x%lx YUV 0x%lx surface",
  1043. lpSurfaceDesc->ddpfPixelFormat.dwFlags,
  1044. lpSurfaceDesc->ddpfPixelFormat.dwFourCC));
  1045. }
  1046. return(DDHAL_DRIVER_NOTHANDLED);
  1047. }
  1048. /******************************Public*Routine******************************\
  1049. * DWORD DdCreateSurface
  1050. *
  1051. * Creates an off-screen surface.
  1052. *
  1053. * We use the Millennium's own off-screen heap manager instead of DirectDraw's
  1054. * so that the MCD and DirectDraw parts can coexist -- at the time of this
  1055. * writing NT has no support for call-backs from the driver to allocate memory,
  1056. * which we need to do to allocate the MCD's back buffer and Z-buffer. So
  1057. * we simply manage all of off-screen memory ourselves.
  1058. *
  1059. * In addition, on the Millennium, YUV surfaces must live in CPU memory.
  1060. *
  1061. \**************************************************************************/
  1062. DWORD DdCreateSurface(
  1063. PDD_CREATESURFACEDATA lpCreateSurface)
  1064. {
  1065. PDEV* ppdev;
  1066. DD_SURFACE_GLOBAL* lpSurface;
  1067. LPDDSURFACEDESC lpSurfaceDesc;
  1068. LONG wWidth;
  1069. LONG wHeight;
  1070. LONG lPitch;
  1071. OH* poh;
  1072. FLATPTR fpVidMem;
  1073. ppdev = (PDEV*) lpCreateSurface->lpDD->dhpdev;
  1074. // On Windows NT, dwSCnt will always be 1, so there will only ever
  1075. // be one entry in the 'lplpSList' array:
  1076. lpSurface = lpCreateSurface->lplpSList[0]->lpGbl;
  1077. lpSurfaceDesc = lpCreateSurface->lpDDSurfaceDesc;
  1078. wWidth = lpSurface->wWidth;
  1079. wHeight = lpSurface->wHeight;
  1080. // We repeat the same checks we did in 'DdCanCreateSurface' because
  1081. // it's possible that an application doesn't call 'DdCanCreateSurface'
  1082. // before calling 'DdCreateSurface'.
  1083. ASSERTDD(lpSurface->ddpfSurface.dwSize == sizeof(DDPIXELFORMAT),
  1084. "NT is supposed to guarantee that ddpfSurface.dwSize is valid");
  1085. // Note that the Millennium cannot do YUV surfaces at 24bpp or at
  1086. // palettized 8bpp:
  1087. if ((lpSurface->ddpfSurface.dwFlags & DDPF_FOURCC) &&
  1088. (lpSurface->ddpfSurface.dwFourCC == FOURCC_YUY2) &&
  1089. ((ppdev->iBitmapFormat == BMF_16BPP) ||
  1090. (ppdev->iBitmapFormat == BMF_32BPP)))
  1091. {
  1092. // Compute the stride of the surface, keeping in mind that it has
  1093. // to be dword aligned. Since the Millennium supports only 16bpp
  1094. // YUV surfaces, this is easy to do:
  1095. lPitch = (2 * wWidth + 3) & ~3;
  1096. // By setting 'fpVidMem' to 'DDHAL_PLEASEALLOC_USERMEM', we can have
  1097. // DirectDraw allocate a piece of user-mode memory of our requested
  1098. // size.
  1099. //
  1100. // Note that we could not simply call EngAllocMem, because that gives
  1101. // us a chunk of kernel-mode memory that is not visible from user-mode.
  1102. // We also cannot call EngAllocUserMem for obscure reasons dealing with
  1103. // the fact EngFreeUserMem must be called from the same process context
  1104. // in which the memory was allocated, and DirectDraw sometimes needs
  1105. // to call DestroySurface from the context of a different process.
  1106. lpSurface->fpVidMem = DDHAL_PLEASEALLOC_USERMEM;
  1107. lpSurface->dwUserMemSize = lPitch * wHeight;
  1108. lpSurface->lPitch = lPitch;
  1109. // DirectDraw expects us to fill in the following fields, too:
  1110. lpSurface->ddpfSurface.dwYUVBitCount = 16;
  1111. lpSurfaceDesc->lPitch = lPitch;
  1112. lpSurfaceDesc->dwFlags |= DDSD_PITCH;
  1113. DISPDBG((0, "Created YUV: %li x %li", wWidth, wHeight));
  1114. return(DDHAL_DRIVER_NOTHANDLED);
  1115. }
  1116. else
  1117. {
  1118. // Due to weirdness of the Matrox, we create non-flippable off-screen
  1119. // surfaces only if running at 8bpp. (The reason is that at 16bpp and
  1120. // 32bpp, we report DDCAPS_BLTSTRETCH so that applications can stretch
  1121. // YUV surfaces via the hardware -- but the hardware is increidbly
  1122. // slow at stretching off-screen RGB surfaces, we don't want off-screen
  1123. // RGB surfaces that are likely to be stretched.)
  1124. if ((ppdev->iBitmapFormat == BMF_8BPP) ||
  1125. ((wWidth == ppdev->cxScreen) && (wHeight == ppdev->cyScreen)))
  1126. {
  1127. // Allocate a space in off-screen memory, using our own heap
  1128. // manager:
  1129. poh = pohAllocate(ppdev, NULL, wWidth, wHeight, FLOH_MAKE_PERMANENT);
  1130. if (poh != NULL)
  1131. {
  1132. fpVidMem = (poh->y * ppdev->lDelta)
  1133. + (poh->x + ppdev->ulYDstOrg) * ppdev->cjPelSize;
  1134. // Flip surfaces, detected by surface requests that are
  1135. // the same size as the current display, have special
  1136. // considerations on the Millennium: they must live entirely
  1137. // in the first two megabytes of video memory:
  1138. if ((wWidth != ppdev->cxScreen) ||
  1139. (wHeight != ppdev->cyScreen) ||
  1140. ((fpVidMem + (wHeight * ppdev->lDelta)) <= 0x200000))
  1141. {
  1142. lpSurface->dwReserved1 = (ULONG_PTR)poh;
  1143. lpSurface->xHint = poh->x;
  1144. lpSurface->yHint = poh->y;
  1145. lpSurface->fpVidMem = fpVidMem;
  1146. lpSurface->lPitch = ppdev->lDelta;
  1147. lpSurfaceDesc->lPitch = ppdev->lDelta;
  1148. lpSurfaceDesc->dwFlags |= DDSD_PITCH;
  1149. // We handled the creation entirely ourselves, so we have to
  1150. // set the return code and return DDHAL_DRIVER_HANDLED:
  1151. lpCreateSurface->ddRVal = DD_OK;
  1152. return(DDHAL_DRIVER_HANDLED);
  1153. }
  1154. // Argh, it's a possible flip surface that we can't use:
  1155. pohFree(ppdev, poh);
  1156. }
  1157. }
  1158. }
  1159. // Fail the call by not setting lpSurface->fpVidMem and returning
  1160. // DDHAL_DRIVER_NOTHANDLED:
  1161. return(DDHAL_DRIVER_NOTHANDLED);
  1162. }
  1163. /******************************Public*Routine******************************\
  1164. * DWORD DdDestroySurface
  1165. *
  1166. * Note that if DirectDraw did the allocation, DDHAL_DRIVER_NOTHANDLED
  1167. * should be returned.
  1168. *
  1169. \**************************************************************************/
  1170. DWORD DdDestroySurface(
  1171. PDD_DESTROYSURFACEDATA lpDestroySurface)
  1172. {
  1173. PDEV* ppdev;
  1174. DD_SURFACE_GLOBAL* lpSurface;
  1175. LONG lPitch;
  1176. ppdev = (PDEV*) lpDestroySurface->lpDD->dhpdev;
  1177. lpSurface = lpDestroySurface->lpDDSurface->lpGbl;
  1178. if (!(lpSurface->ddpfSurface.dwFlags & DDPF_FOURCC))
  1179. {
  1180. pohFree(ppdev, (OH*) lpSurface->dwReserved1);
  1181. // Since we did the original allocation ourselves, we have to
  1182. // return DDHAL_DRIVER_HANDLED here:
  1183. lpDestroySurface->ddRVal = DD_OK;
  1184. return(DDHAL_DRIVER_HANDLED);
  1185. }
  1186. return(DDHAL_DRIVER_NOTHANDLED);
  1187. }
  1188. /**************************************************************************************
  1189. * GetAvailDriverMemory
  1190. *
  1191. * DDraw 'miscellaneous' callback returning the amount of free memory in driver's
  1192. * 'private' heap
  1193. ***************************************************************************************/
  1194. DWORD __stdcall GetAvailDriverMemory (PDD_GETAVAILDRIVERMEMORYDATA pDmd)
  1195. {
  1196. OH *poh;
  1197. OH *pohSentinel;
  1198. LONG lArea;
  1199. PDEV *ppdev;
  1200. ppdev = (PDEV*)(pDmd->lpDD->dhpdev);
  1201. ASSERTDD(ppdev != NULL,"Bad ppdev in GetAvailDriverMemory");
  1202. pohSentinel = &ppdev->heap.ohFree;
  1203. lArea = 0;
  1204. for (poh = pohSentinel->pohNext; poh != pohSentinel; poh = poh->pohNext)
  1205. {
  1206. ASSERTDD(poh->ohState != OH_PERMANENT,
  1207. "Permanent node in free or discardable list");
  1208. lArea += poh->cx * poh->cy;
  1209. }
  1210. pDmd->dwTotal = ppdev->ulTotalAvailVideoMemory;
  1211. pDmd->dwFree = lArea * ppdev->cjPelSize;
  1212. pDmd->ddRVal = DD_OK;
  1213. return DDHAL_DRIVER_HANDLED;
  1214. }
  1215. /******************************Public*Routine******************************\
  1216. * DWORD __stdcall DdGetDriverInfo
  1217. *
  1218. * DESCRIPTION: DirectDraw has had many compatability problems
  1219. * in the past, particularly from adding or modifying
  1220. * members of public structures. GetDriverInfo is an extension
  1221. * architecture that intends to allow DirectDraw to
  1222. * continue evolving, while maintaining backward compatability.
  1223. * This function is passed a GUID which represents some DirectDraw
  1224. * extension. If the driver recognises and supports this extension,
  1225. * it fills out the required data and returns.
  1226. *
  1227. * Callback that registers additional DDraw callbacks
  1228. * in this case used to register GetAvailDriverMemory callback
  1229. *
  1230. \**************************************************************************/
  1231. DWORD __stdcall DdGetDriverInfo(DD_GETDRIVERINFODATA *lpInput)
  1232. {
  1233. DWORD dwSize = 0;
  1234. lpInput->ddRVal = DDERR_CURRENTLYNOTAVAIL;
  1235. if ( IsEqualIID(&lpInput->guidInfo, &GUID_MiscellaneousCallbacks) )
  1236. {
  1237. DD_MISCELLANEOUSCALLBACKS MiscellaneousCallbacks;
  1238. memset(&MiscellaneousCallbacks, 0, sizeof(MiscellaneousCallbacks));
  1239. DISPDBG((0,"Get Miscelaneous Callbacks"));
  1240. dwSize = min(lpInput->dwExpectedSize, sizeof(DD_MISCELLANEOUSCALLBACKS));
  1241. MiscellaneousCallbacks.dwSize = dwSize;
  1242. MiscellaneousCallbacks.dwFlags = DDHAL_MISCCB32_GETAVAILDRIVERMEMORY | 0;
  1243. MiscellaneousCallbacks.GetAvailDriverMemory = GetAvailDriverMemory;
  1244. memcpy(lpInput->lpvData, &MiscellaneousCallbacks, dwSize);
  1245. lpInput->ddRVal = DD_OK;
  1246. }
  1247. return DDHAL_DRIVER_HANDLED;
  1248. }
  1249. /******************************Public*Routine******************************\
  1250. * BOOL DrvGetDirectDrawInfo
  1251. *
  1252. * Will be called twice before DrvEnableDirectDraw is called.
  1253. *
  1254. \**************************************************************************/
  1255. BOOL DrvGetDirectDrawInfo(
  1256. DHPDEV dhpdev,
  1257. DD_HALINFO* pHalInfo,
  1258. DWORD* pdwNumHeaps,
  1259. VIDEOMEMORY* pvmList, // Will be NULL on first call
  1260. DWORD* pdwNumFourCC,
  1261. DWORD* pdwFourCC) // Will be NULL on first call
  1262. {
  1263. BOOL bCanFlip;
  1264. PDEV* ppdev;
  1265. LONGLONG li;
  1266. ppdev = (PDEV*) dhpdev;
  1267. *pdwNumFourCC = 0;
  1268. *pdwNumHeaps = 0;
  1269. // We may not support DirectDraw on this card:
  1270. if (!(ppdev->flStatus & STAT_DIRECTDRAW))
  1271. return(FALSE);
  1272. pHalInfo->dwSize = sizeof(*pHalInfo);
  1273. // Current primary surface attributes:
  1274. pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
  1275. pHalInfo->vmiData.fpPrimary = ppdev->ulYDstOrg * ppdev->cjPelSize;
  1276. pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen;
  1277. pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
  1278. pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta;
  1279. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  1280. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  1281. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cjHwPel * 8;
  1282. if (ppdev->iBitmapFormat == BMF_8BPP)
  1283. {
  1284. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  1285. }
  1286. // These masks will be zero at 8bpp:
  1287. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed;
  1288. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen;
  1289. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
  1290. // Free up as much off-screen memory as possible:
  1291. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  1292. // Capabilities supported:
  1293. pHalInfo->ddCaps.dwCaps = DDCAPS_BLT
  1294. | DDCAPS_BLTCOLORFILL
  1295. | DDCAPS_READSCANLINE;
  1296. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
  1297. | DDSCAPS_PRIMARYSURFACE
  1298. | DDSCAPS_FLIP;
  1299. // We have to tell DirectDraw our preferred off-screen alignment, even
  1300. // if we're doing our own off-screen memory management:
  1301. pHalInfo->vmiData.dwOffscreenAlign = 4;
  1302. // Since we do our own memory allocation, we have to set dwVidMemTotal
  1303. // ourselves. Note that this represents the amount of available off-
  1304. // screen memory, not all of video memory:
  1305. pHalInfo->ddCaps.dwVidMemTotal
  1306. = ppdev->heap.cxMax * ppdev->heap.cyMax * ppdev->cjPelSize;
  1307. // We can do YUV conversions and hardware accelerated stretches at
  1308. // all RGB modes except 24bpp.
  1309. if ((ppdev->iBitmapFormat != BMF_24BPP) &&
  1310. (ppdev->iBitmapFormat != BMF_8BPP))
  1311. {
  1312. pHalInfo->ddCaps.dwCaps |= DDCAPS_BLTSTRETCH
  1313. | DDCAPS_BLTFOURCC;
  1314. pHalInfo->ddCaps.dwFXCaps |= DDFXCAPS_BLTSTRETCHX
  1315. | DDFXCAPS_BLTSTRETCHY;
  1316. // The Millennium supports only one type of YUV format:
  1317. *pdwNumFourCC = 1;
  1318. if (pdwFourCC)
  1319. {
  1320. *pdwFourCC = FOURCC_YUY2;
  1321. }
  1322. }
  1323. // Tell DDraw that we support additional callbacks through DdGetDriverInfo
  1324. pHalInfo->GetDriverInfo = DdGetDriverInfo;
  1325. pHalInfo->dwFlags |= DDHALINFO_GETDRIVERINFOSET;
  1326. return(TRUE);
  1327. }
  1328. /**************************************************************************\
  1329. * ULONG TotalAvailVideoMemory
  1330. *
  1331. * Added for GetAvailVideoMemoty calback
  1332. * Calculate total amount of offscreen video memory without permanent
  1333. * driver allocations. We need to do it here since we won't be able
  1334. * to distinguish between driver's permanent allocation and ddraw's
  1335. * permanent allocation later.
  1336. *
  1337. \**************************************************************************/
  1338. ULONG TotalAvailVideoMemory(PDEV *ppdev)
  1339. {
  1340. OH *poh;
  1341. OH *pohSentinel;
  1342. ULONG ulArea;
  1343. ULONG i;
  1344. ASSERTDD(ppdev != NULL,"Bad ppdev TotalAvailVideoMemory");
  1345. ulArea = 0;
  1346. pohSentinel = &ppdev->heap.ohFree;
  1347. for (i = 2; i != 0; i--)
  1348. {
  1349. for (poh = pohSentinel->pohNext; poh != pohSentinel; poh = poh->pohNext)
  1350. {
  1351. ASSERTDD(poh->ohState != OH_PERMANENT,
  1352. "Permanent node in free or discardable list");
  1353. ulArea += poh->cx * poh->cy;
  1354. }
  1355. // Second time through, loop through the list of discardable
  1356. // rectangles:
  1357. pohSentinel = &ppdev->heap.ohDiscardable;
  1358. }
  1359. return ulArea * ppdev->cjPelSize;
  1360. }
  1361. /******************************Public*Routine******************************\
  1362. * BOOL DrvEnableDirectDraw
  1363. *
  1364. * This function is called by GDI to enable DirectDraw when a DirectDraw
  1365. * program is started and DirectDraw is not already active.
  1366. *
  1367. \**************************************************************************/
  1368. BOOL DrvEnableDirectDraw(
  1369. DHPDEV dhpdev,
  1370. DD_CALLBACKS* pCallBacks,
  1371. DD_SURFACECALLBACKS* pSurfaceCallBacks,
  1372. DD_PALETTECALLBACKS* pPaletteCallBacks)
  1373. {
  1374. PDEV* ppdev;
  1375. ppdev = (PDEV*) dhpdev;
  1376. pCallBacks->WaitForVerticalBlank = DdWaitForVerticalBlank;
  1377. pCallBacks->MapMemory = DdMapMemory;
  1378. pCallBacks->CanCreateSurface = DdCanCreateSurface;
  1379. pCallBacks->CreateSurface = DdCreateSurface;
  1380. pCallBacks->GetScanLine = DdGetScanLine;
  1381. pCallBacks->dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK
  1382. | DDHAL_CB32_MAPMEMORY
  1383. | DDHAL_CB32_CANCREATESURFACE
  1384. | DDHAL_CB32_CREATESURFACE
  1385. | DDHAL_CB32_GETSCANLINE;
  1386. pSurfaceCallBacks->Blt = DdBlt;
  1387. pSurfaceCallBacks->Flip = DdFlip;
  1388. pSurfaceCallBacks->Lock = DdLock;
  1389. pSurfaceCallBacks->GetBltStatus = DdGetBltStatus;
  1390. pSurfaceCallBacks->GetFlipStatus = DdGetFlipStatus;
  1391. pSurfaceCallBacks->DestroySurface = DdDestroySurface;
  1392. pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_BLT
  1393. | DDHAL_SURFCB32_FLIP
  1394. | DDHAL_SURFCB32_LOCK
  1395. | DDHAL_SURFCB32_GETBLTSTATUS
  1396. | DDHAL_SURFCB32_GETFLIPSTATUS
  1397. | DDHAL_SURFCB32_DESTROYSURFACE;
  1398. // Note that we don't call 'vGetDisplayDuration' here, for a couple of
  1399. // reasons:
  1400. //
  1401. // o Because the system is already running, it would be disconcerting
  1402. // to pause the graphics for a good portion of a second just to read
  1403. // the refresh rate;
  1404. // o More importantly, we may not be in graphics mode right now.
  1405. //
  1406. // For both reasons, we always measure the refresh rate when we switch
  1407. // to a new mode.
  1408. // Added for GetAvailDriverMemory callback
  1409. ppdev->ulTotalAvailVideoMemory = TotalAvailVideoMemory(ppdev);
  1410. return(TRUE);
  1411. }
  1412. /******************************Public*Routine******************************\
  1413. * VOID DrvDisableDirectDraw
  1414. *
  1415. * This function is called by GDI when the last active DirectDraw program
  1416. * is quit and DirectDraw will no longer be active.
  1417. *
  1418. \**************************************************************************/
  1419. VOID DrvDisableDirectDraw(
  1420. DHPDEV dhpdev)
  1421. {
  1422. }
  1423. /******************************Public*Routine******************************\
  1424. * VOID vAssertModeDirectDraw
  1425. *
  1426. * This function is called by enable.c when entering or leaving the
  1427. * DOS full-screen character mode.
  1428. *
  1429. \**************************************************************************/
  1430. VOID vAssertModeDirectDraw(
  1431. PDEV* ppdev,
  1432. BOOL bEnabled)
  1433. {
  1434. }
  1435. /******************************Public*Routine******************************\
  1436. * BOOL bEnableDirectDraw
  1437. *
  1438. * This function is called by enable.c when the mode is first initialized,
  1439. * right after the miniport does the mode-set.
  1440. *
  1441. \**************************************************************************/
  1442. BOOL bEnableDirectDraw(
  1443. PDEV* ppdev)
  1444. {
  1445. // We're not going to bother to support accelerated DirectDraw on
  1446. // the Impression or earlier, because they don't have linear frame
  1447. // buffers.
  1448. if (ppdev->ulBoardId == MGA_STORM)
  1449. {
  1450. // Accurately measure the refresh rate for later:
  1451. vGetDisplayDuration(ppdev);
  1452. // DirectDraw is all set to be used on this card:
  1453. ppdev->flStatus |= STAT_DIRECTDRAW;
  1454. }
  1455. return(TRUE);
  1456. }
  1457. /******************************Public*Routine******************************\
  1458. * VOID vDisableDirectDraw
  1459. *
  1460. * This function is called by enable.c when the driver is shutting down.
  1461. *
  1462. \**************************************************************************/
  1463. VOID vDisableDirectDraw(
  1464. PDEV* ppdev)
  1465. {
  1466. }