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.

925 lines
28 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: ddraw32M.c
  3. *
  4. * Implements all the DirectDraw components for the MACH 32 I/O 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 += (WORD)surf->yHint; \
  17. x += (WORD)surf->xHint; \
  18. }
  19. #define M32_CURRENT_VLINE(pjMmBase) ((M32_IW(pjMmBase,VERT_LINE_CNTR) & 0x7ff))
  20. //#define IN_VSYNC ((M32_IW(pjMmBase,DISP_STATUS) & V_SYNC_TOGGLE_BIT) ^ syncToggleSide)
  21. #define M32_WAIT_FOR_IDLE() \
  22. { \
  23. while ( M32_FIFO_SPACE_AVAIL(ppdev, pjMmBase, 16) \
  24. || (M32_IW(pjMmBase,GE_STAT) & GE_BUSY) \
  25. || (M32_IW(pjMmBase,EXT_GE_STATUS) & GE_ACTIVE) \
  26. )\
  27. ;\
  28. }
  29. #define SET_BLT_OFFSET(load,offset,pitch)\
  30. { \
  31. offset >>= 2;\
  32. M32_OB( pjMmBase,SHADOW_SET+1,load); \
  33. M32_OW( pjMmBase,GE_OFFSET_HI,(WORD)((offset >> 16) & 0x000f));\
  34. M32_OW( pjMmBase,GE_OFFSET_LO,(WORD)(offset & 0xffff));\
  35. M32_OW( pjMmBase,GE_PITCH,(WORD)((pitch / pitchAdjuster) >> 3));\
  36. }
  37. #define SET_BLT_SOURCE_OFFSET(offset,pitch) SET_BLT_OFFSET(LOAD_SOURCE,offset,pitch)
  38. #define SET_BLT_DEST_OFFSET(offset,pitch) SET_BLT_OFFSET(LOAD_DEST,offset,pitch)
  39. #define RESET_BLT_OFFSET()\
  40. { \
  41. M32_WAIT_FOR_IDLE(); \
  42. M32_OB( pjMmBase,SHADOW_SET+1, LOAD_SOURCE_AND_DEST);\
  43. M32_OW( pjMmBase,GE_OFFSET_HI, 0);\
  44. M32_OW( pjMmBase,GE_OFFSET_LO,0);\
  45. M32_OW( pjMmBase,GE_PITCH,(WORD)((sysPitch / pitchAdjuster) >> 3));\
  46. }
  47. #define SET_SOURCE_BLT(startX,startY,endX)\
  48. {\
  49. M32_OW( pjMmBase, M32_SRC_X, startX);\
  50. M32_OW( pjMmBase, M32_SRC_Y, startY);\
  51. \
  52. M32_OW( pjMmBase, M32_SRC_X_START,startX);\
  53. M32_OW( pjMmBase, M32_SRC_X_END, endX);\
  54. }
  55. #define SET_DEST_BLT(startX,startY,endX,endY)\
  56. { \
  57. M32_OW( pjMmBase, CUR_X,startX); \
  58. M32_OW( pjMmBase, CUR_Y,startY); \
  59. \
  60. M32_OW( pjMmBase, DEST_X_START,startX);\
  61. M32_OW( pjMmBase, DEST_X_END,endX);\
  62. M32_OW( pjMmBase, DEST_Y_END,endY);\
  63. }
  64. // NT is kind enough to pre-calculate the 2-d surface offset as a 'hint' so
  65. // that we don't have to do the following, which would be 6 DIVs per blt:
  66. //
  67. // y += (offset / pitch)
  68. // x += (offset % pitch) / bytes_per_pixel
  69. #define CONVERT_DEST_TO_ZERO_BASE_REFERENCE(surf)\
  70. {\
  71. convertToGlobalCord(destX, destY, surf);\
  72. convertToGlobalCord(destXEnd, destYEnd, surf);\
  73. }
  74. #define CONVERT_SOURCE_TO_ZERO_BASE_REFERENCE(surf)\
  75. {\
  76. convertToGlobalCord(srcX, srcY, surf);\
  77. convertToGlobalCord(srcXEnd, srcYEnd, surf);\
  78. }
  79. #define M32_DRAW_ENGINE_BUSY(ppdev, pjMmBase) ( \
  80. M32_FIFO_SPACE_AVAIL(ppdev, pjMmBase, 16 ) \
  81. || (M32_IW(pjMmBase,GE_STAT) & GE_BUSY ) \
  82. || (M32_IW(pjMmBase,EXT_GE_STATUS) & GE_ACTIVE) \
  83. )
  84. /*
  85. * currentScanLine
  86. * safe get current scan line
  87. */
  88. static __inline int currentScanLine(BYTE* pjMmBase)
  89. {
  90. WORD lastValue = M32_CURRENT_VLINE(pjMmBase);
  91. WORD currentValue = M32_CURRENT_VLINE(pjMmBase);
  92. while (lastValue != currentValue)
  93. {
  94. lastValue = currentValue;
  95. currentValue = M32_CURRENT_VLINE(pjMmBase);
  96. }
  97. return currentValue;
  98. }
  99. static __inline inVBlank(PDEV* ppdev, BYTE* pjMmBase)
  100. {
  101. int temp;
  102. temp = currentScanLine(pjMmBase);
  103. return ((temp >= ppdev->flipRecord.wstartOfVBlank- 15) || temp < 15);
  104. }
  105. /******************************Public*Routine******************************\
  106. * VOID vGetDisplayDuration32I
  107. *
  108. * Get the length, in EngQueryPerformanceCounter() ticks, of a refresh cycle.
  109. *
  110. * If we could trust the miniport to return back and accurate value for
  111. * the refresh rate, we could use that. Unfortunately, our miniport doesn't
  112. * ensure that it's an accurate value.
  113. *
  114. \**************************************************************************/
  115. #define NUM_VBLANKS_TO_MEASURE 1
  116. #define NUM_MEASUREMENTS_TO_TAKE 8
  117. VOID vGetDisplayDuration32M(PDEV* ppdev)
  118. {
  119. BYTE* pjMmBase;
  120. LONG i;
  121. LONG j;
  122. LONGLONG li;
  123. LONGLONG liMin;
  124. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  125. pjMmBase = ppdev->pjMmBase;
  126. ppdev->flipRecord.wstartOfVBlank = M32_IW(pjMmBase, R_V_DISP);
  127. // Warm up EngQUeryPerformanceCounter to make sure it's in the working
  128. // set:
  129. EngQueryPerformanceCounter(&li);
  130. // Unfortunately, since NT is a proper multitasking system, we can't
  131. // just disable interrupts to take an accurate reading. We also can't
  132. // do anything so goofy as dynamically change our thread's priority to
  133. // real-time.
  134. //
  135. // So we just do a bunch of short measurements and take the minimum.
  136. //
  137. // It would be 'okay' if we got a result that's longer than the actual
  138. // VBlank cycle time -- nothing bad would happen except that the app
  139. // would run a little slower. We don't want to get a result that's
  140. // shorter than the actual VBlank cycle time -- that could cause us
  141. // to start drawing over a frame before the Flip has occured.
  142. while (inVBlank( ppdev, pjMmBase))
  143. ;
  144. while (!(inVBlank( ppdev, pjMmBase)))
  145. ;
  146. for (i = 0; i < NUM_MEASUREMENTS_TO_TAKE; i++)
  147. {
  148. // We're at the start of the VBlank active cycle!
  149. EngQueryPerformanceCounter(&aliMeasurement[i]);
  150. // Okay, so life in a multi-tasking environment isn't all that
  151. // simple. What if we had taken a context switch just before
  152. // the above EngQueryPerformanceCounter call, and now were half
  153. // way through the VBlank inactive cycle? Then we would measure
  154. // only half a VBlank cycle, which is obviously bad. The worst
  155. // thing we can do is get a time shorter than the actual VBlank
  156. // cycle time.
  157. //
  158. // So we solve this by making sure we're in the VBlank active
  159. // time before and after we query the time. If it's not, we'll
  160. // sync up to the next VBlank (it's okay to measure this period --
  161. // it will be guaranteed to be longer than the VBlank cycle and
  162. // will likely be thrown out when we select the minimum sample).
  163. // There's a chance that we'll take a context switch and return
  164. // just before the end of the active VBlank time -- meaning that
  165. // the actual measured time would be less than the true amount --
  166. // but since the VBlank is active less than 1% of the time, this
  167. // means that we would have a maximum of 1% error approximately
  168. // 1% of the times we take a context switch. An acceptable risk.
  169. //
  170. // This next line will cause us wait if we're no longer in the
  171. // VBlank active cycle as we should be at this point:
  172. while (!(inVBlank( ppdev, pjMmBase)))
  173. ;
  174. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  175. {
  176. while (inVBlank( ppdev, pjMmBase))
  177. ;
  178. while (!(inVBlank( ppdev, pjMmBase)))
  179. ;
  180. }
  181. }
  182. EngQueryPerformanceCounter(&aliMeasurement[NUM_MEASUREMENTS_TO_TAKE]);
  183. // Use the minimum:
  184. liMin = aliMeasurement[1] - aliMeasurement[0];
  185. DISPDBG((10, "Refresh count: %li - %li", 1, (ULONG) liMin));
  186. for (i = 2; i <= NUM_MEASUREMENTS_TO_TAKE; i++)
  187. {
  188. li = aliMeasurement[i] - aliMeasurement[i - 1];
  189. DISPDBG((10, " %li - %li", i, (ULONG) li));
  190. if (li < liMin)
  191. liMin = li;
  192. }
  193. // Round the result:
  194. ppdev->flipRecord.liFlipDuration
  195. = (DWORD) (liMin + (NUM_VBLANKS_TO_MEASURE / 2)) / NUM_VBLANKS_TO_MEASURE;
  196. DISPDBG((10, "Frequency %li.%03li Hz",
  197. (ULONG) (EngQueryPerformanceFrequency(&li),
  198. li / ppdev->flipRecord.liFlipDuration),
  199. (ULONG) (EngQueryPerformanceFrequency(&li),
  200. ((li * 1000) / ppdev->flipRecord.liFlipDuration) % 1000)));
  201. ppdev->flipRecord.liFlipTime = aliMeasurement[NUM_MEASUREMENTS_TO_TAKE];
  202. ppdev->flipRecord.bFlipFlag = FALSE;
  203. ppdev->flipRecord.fpFlipFrom = 0;
  204. }
  205. /******************************Public*Routine******************************\
  206. * HRESULT vUpdateFlipStatus32M
  207. *
  208. * Checks and sees if the most recent flip has occurred.
  209. *
  210. \**************************************************************************/
  211. HRESULT vUpdateFlipStatus32M(
  212. PDEV* ppdev,
  213. FLATPTR fpVidMem)
  214. {
  215. BYTE* pjMmBase;
  216. LONGLONG liTime;
  217. pjMmBase = ppdev->pjMmBase;
  218. if ((ppdev->flipRecord.bFlipFlag) &&
  219. ((fpVidMem == 0) || (fpVidMem == ppdev->flipRecord.fpFlipFrom)))
  220. {
  221. if (inVBlank( ppdev, pjMmBase))
  222. {
  223. if (ppdev->flipRecord.bWasEverInDisplay)
  224. {
  225. ppdev->flipRecord.bHaveEverCrossedVBlank = TRUE;
  226. }
  227. }
  228. else //In display
  229. {
  230. if( ppdev->flipRecord.bHaveEverCrossedVBlank )
  231. {
  232. ppdev->flipRecord.bFlipFlag = FALSE;
  233. return(DD_OK);
  234. }
  235. ppdev->flipRecord.bWasEverInDisplay = TRUE;
  236. }
  237. EngQueryPerformanceCounter(&liTime);
  238. if (liTime - ppdev->flipRecord.liFlipTime
  239. <= ppdev->flipRecord.liFlipDuration)
  240. {
  241. return(DDERR_WASSTILLDRAWING);
  242. }
  243. ppdev->flipRecord.bFlipFlag = FALSE;
  244. }
  245. return(DD_OK);
  246. }
  247. /******************************Public*Routine******************************\
  248. * DWORD DdBlt32M
  249. *
  250. \**************************************************************************/
  251. DWORD DdBlt32M(
  252. PDD_BLTDATA lpBlt)
  253. {
  254. HRESULT ddrval;
  255. DWORD destOffset;
  256. WORD destPitch;
  257. WORD destX;
  258. WORD destXEnd;
  259. WORD destY;
  260. WORD destYEnd;
  261. WORD direction;
  262. WORD remainder;
  263. DWORD dwFlags;
  264. WORD height;
  265. RECTL rDest;
  266. RECTL rSrc;
  267. BYTE rop;
  268. DWORD sourceOffset;
  269. WORD srcPitch;
  270. WORD srcX;
  271. WORD srcXEnd;
  272. WORD srcY;
  273. WORD srcYEnd;
  274. WORD pitchAdjuster;
  275. WORD sysPitch;
  276. PDD_SURFACE_LOCAL srcSurfx;
  277. PDD_SURFACE_GLOBAL srcSurf;
  278. PDD_SURFACE_LOCAL destSurfx;
  279. PDD_SURFACE_GLOBAL destSurf;
  280. PDEV* ppdev;
  281. BYTE* pjMmBase;
  282. ppdev = (PDEV*) lpBlt->lpDD->dhpdev;
  283. pjMmBase = ppdev->pjMmBase;
  284. destSurfx = lpBlt->lpDDDestSurface;
  285. destSurf = destSurfx->lpGbl;
  286. sysPitch = (WORD)ppdev->lDelta;
  287. pitchAdjuster = (WORD)(ppdev->cBitsPerPel) /8;
  288. /*
  289. * is a flip in progress?
  290. */
  291. ddrval = vUpdateFlipStatus32M(ppdev, destSurf->fpVidMem );
  292. if( ddrval != DD_OK )
  293. {
  294. lpBlt->ddRVal = ddrval;
  295. return DDHAL_DRIVER_HANDLED;
  296. }
  297. /*
  298. * If async, then only work if bltter isn't busy
  299. * This should probably be a little more specific to each call, but
  300. * waiting for 16 is pretty close
  301. */
  302. dwFlags = lpBlt->dwFlags;
  303. if( dwFlags & DDBLT_ASYNC )
  304. {
  305. if( M32_FIFO_SPACE_AVAIL(ppdev, pjMmBase, 16 ))
  306. {
  307. lpBlt->ddRVal = DDERR_WASSTILLDRAWING;
  308. return DDHAL_DRIVER_HANDLED;
  309. }
  310. }
  311. /*
  312. * copy src/dest rects
  313. */
  314. rDest = lpBlt->rDest;
  315. destX = (WORD)rDest.left;
  316. destXEnd = (WORD)rDest.right;
  317. destY = (WORD)rDest.top;
  318. destYEnd = (WORD)rDest.bottom;
  319. destPitch = (WORD)destSurf->lPitch;
  320. destOffset = (DWORD)(destSurf->fpVidMem) ;
  321. if (!(dwFlags & DDBLT_ROP))
  322. {
  323. if( dwFlags & DDBLT_COLORFILL )
  324. {
  325. {
  326. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 9);
  327. CONVERT_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  328. M32_OW( pjMmBase,DP_CONFIG,COLOR_FIL_BLT);
  329. M32_OW( pjMmBase,ALU_FG_FN,MIX_FN_S);
  330. M32_OW( pjMmBase, FRGD_COLOR,(WORD)lpBlt->bltFX.dwFillColor);
  331. SET_DEST_BLT(destX,destY,destXEnd,destYEnd);
  332. }
  333. lpBlt->ddRVal = DD_OK;
  334. return DDHAL_DRIVER_HANDLED;
  335. }
  336. else
  337. {
  338. return DDHAL_DRIVER_NOTHANDLED;
  339. }
  340. }
  341. //
  342. // Must be a SRCCOPY ROP if ew get here....
  343. //
  344. srcSurfx = lpBlt->lpDDSrcSurface;
  345. if (lpBlt->lpDDSrcSurface)
  346. {
  347. srcSurf = srcSurfx->lpGbl;
  348. rSrc = lpBlt->rSrc;
  349. srcX = (WORD)rSrc.left;
  350. srcXEnd = (WORD)rSrc.right;
  351. srcY = (WORD)rSrc.top;
  352. srcYEnd = (WORD)rSrc.bottom;
  353. srcPitch = (WORD)srcSurf->lPitch;
  354. sourceOffset = (DWORD)(srcSurf->fpVidMem) ;
  355. direction = TOP_TO_BOTTOM;
  356. if ( (destSurf == srcSurf)
  357. && (srcXEnd > destX)
  358. && (srcYEnd > destY)
  359. && (destXEnd > srcX)
  360. && (destYEnd > srcY)
  361. && (
  362. ((srcY == destY) && (destX > srcX) )
  363. || ((srcY != destY) && (destY > srcY) )
  364. )
  365. )
  366. {
  367. direction = BOTTOM_TO_TOP;
  368. srcX = (WORD)rSrc.right;
  369. srcXEnd = (WORD)rSrc.left;
  370. srcY = (WORD)rSrc.bottom-1;
  371. destX = (WORD)rDest.right;
  372. destXEnd = (WORD)rDest.left;
  373. destY = (WORD)rDest.bottom-1;
  374. destYEnd = (WORD)rDest.top-1;
  375. }
  376. }
  377. /*
  378. * get offset, width, and height for source
  379. */
  380. rop = (BYTE) (lpBlt->bltFX.dwROP >> 16);
  381. if( dwFlags & DDBLT_ROP )
  382. {
  383. if (rop == (SRCCOPY >> 16))
  384. { // Transparent BLT
  385. if ( dwFlags & DDBLT_KEYDESTOVERRIDE )
  386. {
  387. CONVERT_SOURCE_TO_ZERO_BASE_REFERENCE(srcSurf);
  388. CONVERT_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  389. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase,10);
  390. M32_OW( pjMmBase, DP_CONFIG, VID_MEM_BLT);
  391. M32_OW( pjMmBase, ALU_FG_FN, MIX_FN_S);
  392. M32_OW( pjMmBase, SRC_Y_DIR, direction);
  393. M32_OW( pjMmBase, MULTIFUNC_CNTL, PIXEL_CTRL | DEST_NOT_EQ_COLOR_CMP );
  394. M32_OW( pjMmBase, CMP_COLOR, lpBlt->bltFX.ddckDestColorkey.dwColorSpaceLowValue );
  395. SET_SOURCE_BLT(srcX,srcY,srcXEnd);
  396. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase,10);
  397. SET_DEST_BLT(destX,destY,destXEnd,destYEnd);
  398. //new
  399. RESET_BLT_OFFSET();
  400. M32_OW(pjMmBase, MULTIFUNC_CNTL,PIXEL_CTRL | DEST_ALWAY_OVERWRITE);
  401. }
  402. else
  403. { // Not transparent
  404. CONVERT_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  405. CONVERT_SOURCE_TO_ZERO_BASE_REFERENCE(srcSurf);
  406. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase,12);
  407. M32_OW( pjMmBase, DP_CONFIG,VID_MEM_BLT);
  408. M32_OW( pjMmBase, ALU_FG_FN,MIX_FN_S);
  409. M32_OW( pjMmBase, SRC_Y_DIR,direction);
  410. SET_SOURCE_BLT(srcX,srcY,srcXEnd);
  411. SET_DEST_BLT(destX,destY,destXEnd,destYEnd);
  412. }
  413. }
  414. }
  415. else
  416. return DDHAL_DRIVER_NOTHANDLED;
  417. lpBlt->ddRVal = DD_OK;
  418. return DDHAL_DRIVER_HANDLED;
  419. }
  420. /******************************Public*Routine******************************\
  421. * DWORD DdFlip32
  422. *
  423. \**************************************************************************/
  424. DWORD DdFlip32M(
  425. PDD_FLIPDATA lpFlip)
  426. {
  427. PDEV* ppdev;
  428. BYTE* pjMmBase;
  429. HRESULT ddrval;
  430. WORD highVidMem;
  431. WORD lowVidMem;
  432. ULONG ulMemoryOffset;
  433. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  434. pjMmBase = ppdev->pjMmBase;
  435. // Is the current flip still in progress?
  436. //
  437. // Don't want a flip to work until after the last flip is done,
  438. // so we ask for the general flip status and ignore the vmem.
  439. ddrval = vUpdateFlipStatus32M(ppdev, 0);
  440. if ((ddrval != DD_OK) || (M32_DRAW_ENGINE_BUSY( ppdev,pjMmBase)))
  441. {
  442. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  443. return(DDHAL_DRIVER_HANDLED);
  444. }
  445. ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem >> 2);
  446. // Make sure that the border/blanking period isn't active; wait if
  447. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  448. // that will increase the odds that we can't flip the next time:
  449. while (inVBlank(ppdev, pjMmBase))
  450. ;
  451. // Do the flip
  452. highVidMem = M32_IW(pjMmBase,CRT_OFFSET_HI) & 0xfffc | (WORD)(ulMemoryOffset >>16);
  453. lowVidMem = (WORD)(ulMemoryOffset & 0xffff);
  454. if (inVBlank( ppdev, pjMmBase))
  455. {
  456. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  457. return DDHAL_DRIVER_HANDLED;
  458. }
  459. M32_CHECK_FIFO_SPACE(ppdev, pjMmBase,2);
  460. M32_OW_DIRECT( pjMmBase,CRT_OFFSET_HI, highVidMem);
  461. M32_OW_DIRECT( pjMmBase,CRT_OFFSET_LO, lowVidMem);
  462. // Remember where and when we were when we did the flip:
  463. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  464. ppdev->flipRecord.bFlipFlag = TRUE;
  465. ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
  466. ppdev->flipRecord.bWasEverInDisplay = FALSE;
  467. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  468. if( inVBlank( ppdev, pjMmBase) )
  469. {
  470. ppdev->flipRecord.wFlipScanLine = 0;
  471. }
  472. else
  473. {
  474. ppdev->flipRecord.wFlipScanLine = currentScanLine(pjMmBase);
  475. }
  476. lpFlip->ddRVal = DD_OK;
  477. return(DDHAL_DRIVER_HANDLED);
  478. }
  479. /******************************Public*Routine******************************\
  480. * DWORD DdLock32M
  481. *
  482. \**************************************************************************/
  483. DWORD DdLock32M(
  484. PDD_LOCKDATA lpLock)
  485. {
  486. PDEV* ppdev;
  487. HRESULT ddrval;
  488. ppdev = (PDEV*) lpLock->lpDD->dhpdev;
  489. // Check to see if any pending physical flip has occurred.
  490. // Don't allow a lock if a blt is in progress:
  491. ddrval = vUpdateFlipStatus32M(ppdev, lpLock->lpDDSurface->lpGbl->fpVidMem);
  492. if (ddrval != DD_OK)
  493. {
  494. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  495. return(DDHAL_DRIVER_HANDLED);
  496. }
  497. // Here's one of the places where the Windows 95 and Windows NT DirectDraw
  498. // implementations differ: on Windows NT, you should watch for
  499. // DDLOCK_WAIT and loop in the driver while the accelerator is busy.
  500. // On Windows 95, it doesn't really matter.
  501. //
  502. // (The reason is that Windows NT allows applications to draw directly
  503. // to the frame buffer even while the accelerator is running, and does
  504. // not synchronize everything on the Win16Lock. Note that on Windows NT,
  505. // it is even possible for multiple threads to be holding different
  506. // DirectDraw surface locks at the same time.)
  507. if (lpLock->dwFlags & DDLOCK_WAIT)
  508. {
  509. do {} while (M32_DRAW_ENGINE_BUSY(ppdev, ppdev->pjMmBase));
  510. }
  511. else if (M32_DRAW_ENGINE_BUSY(ppdev, ppdev->pjMmBase))
  512. {
  513. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  514. return(DDHAL_DRIVER_HANDLED);
  515. }
  516. return(DDHAL_DRIVER_NOTHANDLED);
  517. }
  518. /******************************Public*Routine******************************\
  519. * DWORD DdGetBltStatus32M
  520. *
  521. * Doesn't currently really care what surface is specified, just checks
  522. * and goes.
  523. *
  524. \**************************************************************************/
  525. DWORD DdGetBltStatus32M(
  526. PDD_GETBLTSTATUSDATA lpGetBltStatus)
  527. {
  528. PDEV* ppdev;
  529. HRESULT ddRVal;
  530. ppdev = (PDEV*) lpGetBltStatus->lpDD->dhpdev;
  531. ddRVal = DD_OK;
  532. if (lpGetBltStatus->dwFlags == DDGBS_CANBLT)
  533. {
  534. // DDGBS_CANBLT case: can we add a blt?
  535. ddRVal = vUpdateFlipStatus32M(ppdev,
  536. lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
  537. if (ddRVal == DD_OK)
  538. {
  539. // There was no flip going on, so is there room in the FIFO
  540. // to add a blt?
  541. if (M32_FIFO_SPACE_AVAIL(ppdev,ppdev->pjMmBase,15)) // Should match DdBlt//XXX
  542. {
  543. ddRVal = DDERR_WASSTILLDRAWING;
  544. }
  545. }
  546. }
  547. else
  548. {
  549. // DDGBS_ISBLTDONE case: is a blt in progress?
  550. if (M32_DRAW_ENGINE_BUSY( ppdev,ppdev->pjMmBase))
  551. {
  552. ddRVal = DDERR_WASSTILLDRAWING;
  553. }
  554. }
  555. lpGetBltStatus->ddRVal = ddRVal;
  556. return(DDHAL_DRIVER_HANDLED);
  557. }
  558. /******************************Public*Routine******************************\
  559. * DWORD DdGetFlipStatus32M
  560. *
  561. * If the display has gone through one refresh cycle since the flip
  562. * occurred, we return DD_OK. If it has not gone through one refresh
  563. * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
  564. * is still busy "drawing" the flipped page. We also return
  565. * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted
  566. * to know if they could flip yet.
  567. *
  568. \**************************************************************************/
  569. DWORD DdGetFlipStatus32M(
  570. PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  571. {
  572. PDEV* ppdev;
  573. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  574. // We don't want a flip to work until after the last flip is done,
  575. // so we ask for the general flip status and ignore the vmem:
  576. lpGetFlipStatus->ddRVal = vUpdateFlipStatus32M(ppdev, 0);
  577. // Check if the bltter is busy if someone wants to know if they can
  578. // flip:
  579. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  580. {
  581. if ((lpGetFlipStatus->ddRVal == DD_OK) && (M32_DRAW_ENGINE_BUSY( ppdev,ppdev->pjMmBase)))
  582. {
  583. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  584. }
  585. }
  586. return(DDHAL_DRIVER_HANDLED);
  587. }
  588. /******************************Public*Routine******************************\
  589. * DWORD DdWaitForVerticalBlank32M
  590. *
  591. \**************************************************************************/
  592. DWORD DdWaitForVerticalBlank32M(
  593. PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  594. {
  595. PDEV* ppdev;
  596. BYTE* pjMmBase;
  597. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  598. pjMmBase = ppdev->pjMmBase;
  599. lpWaitForVerticalBlank->ddRVal = DD_OK;
  600. switch (lpWaitForVerticalBlank->dwFlags)
  601. {
  602. case DDWAITVB_I_TESTVB:
  603. // If TESTVB, it's just a request for the current vertical blank
  604. // status:
  605. if (inVBlank( ppdev,pjMmBase))
  606. lpWaitForVerticalBlank->bIsInVB = TRUE;
  607. else
  608. lpWaitForVerticalBlank->bIsInVB = FALSE;
  609. return(DDHAL_DRIVER_HANDLED);
  610. case DDWAITVB_BLOCKBEGIN:
  611. // If BLOCKBEGIN is requested, we wait until the vertical blank
  612. // is over, and then wait for the display period to end:
  613. while (inVBlank( ppdev,pjMmBase))
  614. ;
  615. while (!inVBlank( ppdev,pjMmBase))
  616. ;
  617. return(DDHAL_DRIVER_HANDLED);
  618. case DDWAITVB_BLOCKEND:
  619. // If BLOCKEND is requested, we wait for the vblank interval to end:
  620. while (!(inVBlank( ppdev,pjMmBase)))
  621. ;
  622. while (inVBlank( ppdev,pjMmBase))
  623. ;
  624. return(DDHAL_DRIVER_HANDLED);
  625. }
  626. return(DDHAL_DRIVER_NOTHANDLED);
  627. }
  628. /******************************Public*Routine******************************\
  629. * DWORD DdGetScanLine32M
  630. *
  631. \**************************************************************************/
  632. DWORD DdGetScanLine32M(
  633. PDD_GETSCANLINEDATA lpGetScanLine)
  634. {
  635. PDEV* ppdev;
  636. BYTE* pjMmBase;
  637. ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
  638. pjMmBase = ppdev->pjMmBase;
  639. lpGetScanLine->dwScanLine = M32_CURRENT_VLINE(pjMmBase);
  640. lpGetScanLine->ddRVal = DD_OK;
  641. return(DDHAL_DRIVER_HANDLED);
  642. }
  643. /******************************Public*Routine******************************\
  644. * BOOL DrvGetDirectDrawInfo32M
  645. *
  646. * Will be called before DrvEnableDirectDraw is called.
  647. *
  648. \**************************************************************************/
  649. BOOL DrvGetDirectDrawInfo32M(
  650. DHPDEV dhpdev,
  651. DD_HALINFO* pHalInfo,
  652. DWORD* pdwNumHeaps,
  653. VIDEOMEMORY* pvmList, // Will be NULL on first call
  654. DWORD* pdwNumFourCC,
  655. DWORD* pdwFourCC) // Will be NULL on first call
  656. {
  657. BOOL bCanFlip;
  658. PDEV* ppdev;
  659. LONGLONG li;
  660. OH *poh;
  661. DWORD i;
  662. ppdev = (PDEV*) dhpdev;
  663. DISPDBG((10,"DrvGetDirectDrawInfo M32"));
  664. pHalInfo->dwSize = sizeof(*pHalInfo);
  665. // Current primary surface attributes:
  666. pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
  667. pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen;
  668. pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
  669. pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta;
  670. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  671. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  672. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cBitsPerPel;
  673. if (ppdev->iBitmapFormat == BMF_8BPP)
  674. {
  675. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  676. }
  677. // These masks will be zero at 8bpp:
  678. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed;
  679. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen;
  680. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
  681. // We can't do any accelerations on the Mach32 above 16bpp -- the only
  682. // DirectDraw support we can provide is direct frame buffer access.
  683. if (ppdev->iBitmapFormat < BMF_24BPP)
  684. {
  685. // Set up the pointer to the first available video memory after
  686. // the primary surface:
  687. bCanFlip = FALSE;
  688. // Free up as much off-screen memory as possible:
  689. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  690. // Now simply reserve the biggest chunks for use by DirectDraw:
  691. poh = ppdev->pohDirectDraw;
  692. if (poh == NULL)
  693. {
  694. poh = pohAllocate(ppdev,
  695. NULL,
  696. ppdev->heap.cxMax,
  697. ppdev->heap.cyMax,
  698. FLOH_MAKE_PERMANENT);
  699. ppdev->pohDirectDraw = poh;
  700. }
  701. // this will work as is if using the NT common 2-d heap code.
  702. if (poh != NULL)
  703. {
  704. *pdwNumHeaps = 1;
  705. // Check to see if we can allocate memory to the right of the visible
  706. // surface.
  707. // Fill in the list of off-screen rectangles if we've been asked
  708. // to do so:
  709. if (pvmList != NULL)
  710. {
  711. DISPDBG((10, "DirectDraw gets %li x %li surface at (%li, %li)",
  712. poh->cx, poh->cy, poh->x, poh->y));
  713. pvmList->dwFlags = VIDMEM_ISRECTANGULAR;
  714. pvmList->fpStart = (poh->y * ppdev->lDelta)
  715. + (poh->x * ppdev->cjPelSize);
  716. pvmList->dwWidth = poh->cx * ppdev->cjPelSize;
  717. pvmList->dwHeight = poh->cy;
  718. pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  719. if ((DWORD) ppdev->cyScreen <= pvmList->dwHeight)
  720. {
  721. bCanFlip = TRUE;
  722. }
  723. DISPDBG((10,"CanFlip = %d", bCanFlip));
  724. }
  725. }
  726. pHalInfo->ddCaps.dwCaps = DDCAPS_BLT
  727. | DDCAPS_COLORKEY
  728. | DDCAPS_BLTCOLORFILL
  729. | DDCAPS_READSCANLINE;
  730. pHalInfo->ddCaps.dwCKeyCaps = 0;
  731. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
  732. | DDSCAPS_PRIMARYSURFACE;
  733. if (bCanFlip)
  734. {
  735. pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
  736. }
  737. }
  738. else
  739. {
  740. pHalInfo->ddCaps.dwCaps = DDCAPS_READSCANLINE;
  741. }
  742. // dword alignment must be guaranteed for off-screen surfaces:
  743. pHalInfo->vmiData.dwOffscreenAlign = 8;
  744. DISPDBG((10,"DrvGetDirectDrawInfo exit"));
  745. return(TRUE);
  746. }