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.

919 lines
27 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: ddraw32I.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 I32_CURRENT_VLINE(pjIoBase) ((I32_IW(pjIoBase,VERT_LINE_CNTR) & 0x7ff))
  20. //#define IN_VSYNC ((I32_IW(pjIoBase,DISP_STATUS) & V_SYNC_TOGGLE_BIT) ^ syncToggleSide)
  21. #define I32_WAIT_FOR_IDLE() \
  22. { \
  23. while ( I32_FIFO_SPACE_AVAIL(ppdev, pjIoBase, 16) \
  24. || (I32_IW(pjIoBase,GE_STAT) & GE_BUSY) \
  25. || (I32_IW(pjIoBase,EXT_GE_STATUS) & GE_ACTIVE) \
  26. )\
  27. ;\
  28. }
  29. #define SET_BLT_OFFSET(load,offset,pitch)\
  30. { \
  31. offset >>= 2;\
  32. I32_OB( pjIoBase,SHADOW_SET+1,load); \
  33. I32_OW( pjIoBase,GE_OFFSET_HI,(WORD)((offset >> 16) & 0x000f));\
  34. I32_OW( pjIoBase,GE_OFFSET_LO,(WORD)(offset & 0xffff));\
  35. I32_OW( pjIoBase,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. I32_WAIT_FOR_IDLE(); \
  42. I32_OB( pjIoBase,SHADOW_SET+1, LOAD_SOURCE_AND_DEST);\
  43. I32_OW( pjIoBase,GE_OFFSET_HI, 0);\
  44. I32_OW( pjIoBase,GE_OFFSET_LO,0);\
  45. I32_OW( pjIoBase,GE_PITCH,(WORD)((sysPitch / pitchAdjuster) >> 3));\
  46. }
  47. #define SET_SOURCE_BLT(startX,startY,endX)\
  48. {\
  49. I32_OW( pjIoBase, M32_SRC_X, startX);\
  50. I32_OW( pjIoBase, M32_SRC_Y, startY);\
  51. \
  52. I32_OW( pjIoBase, M32_SRC_X_START,startX);\
  53. I32_OW( pjIoBase, M32_SRC_X_END, endX);\
  54. }
  55. #define SET_DEST_BLT(startX,startY,endX,endY)\
  56. { \
  57. I32_OW( pjIoBase, CUR_X,startX); \
  58. I32_OW( pjIoBase, CUR_Y,startY); \
  59. \
  60. I32_OW( pjIoBase, DEST_X_START,startX);\
  61. I32_OW( pjIoBase, DEST_X_END,endX);\
  62. I32_OW( pjIoBase, 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 I32_DRAW_ENGINE_BUSY(ppdev, pjIoBase) ( \
  80. I32_FIFO_SPACE_AVAIL(ppdev, pjIoBase, 16 ) \
  81. || (I32_IW(pjIoBase,GE_STAT) & GE_BUSY ) \
  82. || (I32_IW(pjIoBase,EXT_GE_STATUS) & GE_ACTIVE) \
  83. )
  84. /*
  85. * currentScanLine
  86. * safe get current scan line
  87. */
  88. static __inline int currentScanLine(BYTE* pjIoBase)
  89. {
  90. WORD lastValue = I32_CURRENT_VLINE(pjIoBase);
  91. WORD currentValue = I32_CURRENT_VLINE(pjIoBase);
  92. while (lastValue != currentValue)
  93. {
  94. lastValue = currentValue;
  95. currentValue = I32_CURRENT_VLINE(pjIoBase);
  96. }
  97. return currentValue;
  98. }
  99. static __inline inVBlank(PDEV* ppdev, BYTE* pjIoBase)
  100. {
  101. int temp;
  102. temp = currentScanLine(pjIoBase);
  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 vGetDisplayDuration32I(PDEV* ppdev)
  118. {
  119. BYTE* pjIoBase;
  120. LONG i;
  121. LONG j;
  122. LONGLONG li;
  123. LONGLONG liMin;
  124. LONGLONG aliMeasurement[NUM_MEASUREMENTS_TO_TAKE + 1];
  125. pjIoBase = ppdev->pjIoBase;
  126. ppdev->flipRecord.wstartOfVBlank = I32_IW(pjIoBase, 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, pjIoBase))
  143. ;
  144. while (!(inVBlank( ppdev, pjIoBase)))
  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, pjIoBase)))
  173. ;
  174. for (j = 0; j < NUM_VBLANKS_TO_MEASURE; j++)
  175. {
  176. while (inVBlank( ppdev, pjIoBase))
  177. ;
  178. while (!(inVBlank( ppdev, pjIoBase)))
  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 vUpdateFlipStatus32I
  207. *
  208. * Checks and sees if the most recent flip has occurred.
  209. *
  210. \**************************************************************************/
  211. HRESULT vUpdateFlipStatus32I(
  212. PDEV* ppdev,
  213. FLATPTR fpVidMem)
  214. {
  215. BYTE* pjIoBase;
  216. LONGLONG liTime;
  217. pjIoBase = ppdev->pjIoBase;
  218. if ((ppdev->flipRecord.bFlipFlag) &&
  219. ((fpVidMem == 0) || (fpVidMem == ppdev->flipRecord.fpFlipFrom)))
  220. {
  221. if (inVBlank( ppdev, pjIoBase))
  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 DdBlt32I
  249. *
  250. \**************************************************************************/
  251. DWORD DdBlt32I(
  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* pjIoBase;
  282. ppdev = (PDEV*) lpBlt->lpDD->dhpdev;
  283. pjIoBase = ppdev->pjIoBase;
  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 = vUpdateFlipStatus32I(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( I32_FIFO_SPACE_AVAIL(ppdev, pjIoBase, 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. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 9);
  327. CONVERT_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  328. I32_OW( pjIoBase,DP_CONFIG,COLOR_FIL_BLT);
  329. I32_OW( pjIoBase,ALU_FG_FN,MIX_FN_S);
  330. I32_OW( pjIoBase, 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_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  388. CONVERT_SOURCE_TO_ZERO_BASE_REFERENCE(srcSurf);
  389. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase,12);
  390. I32_OW( pjIoBase, DP_CONFIG, VID_MEM_BLT);
  391. I32_OW( pjIoBase, ALU_FG_FN, MIX_FN_S);
  392. I32_OW( pjIoBase, SRC_Y_DIR, direction);
  393. I32_OW( pjIoBase, MULTIFUNC_CNTL, PIXEL_CTRL | DEST_NOT_EQ_COLOR_CMP );
  394. I32_OW( pjIoBase, CMP_COLOR, lpBlt->bltFX.ddckDestColorkey.dwColorSpaceLowValue );
  395. SET_SOURCE_BLT(srcX,srcY,srcXEnd);
  396. SET_DEST_BLT(destX,destY,destXEnd,destYEnd);
  397. }
  398. else
  399. { // Not transparent
  400. CONVERT_DEST_TO_ZERO_BASE_REFERENCE(destSurf);
  401. CONVERT_SOURCE_TO_ZERO_BASE_REFERENCE(srcSurf);
  402. I32_CHECK_FIFO_SPACE(ppdev, pjIoBase,12);
  403. I32_OW( pjIoBase, DP_CONFIG,VID_MEM_BLT);
  404. I32_OW( pjIoBase, ALU_FG_FN,MIX_FN_S);
  405. I32_OW( pjIoBase, SRC_Y_DIR,direction);
  406. SET_SOURCE_BLT(srcX,srcY,srcXEnd);
  407. SET_DEST_BLT(destX,destY,destXEnd,destYEnd);
  408. }
  409. }
  410. }
  411. else
  412. return DDHAL_DRIVER_NOTHANDLED;
  413. lpBlt->ddRVal = DD_OK;
  414. return DDHAL_DRIVER_HANDLED;
  415. }
  416. /******************************Public*Routine******************************\
  417. * DWORD DdFlip32
  418. *
  419. \**************************************************************************/
  420. DWORD DdFlip32I(
  421. PDD_FLIPDATA lpFlip)
  422. {
  423. PDEV* ppdev;
  424. BYTE* pjIoBase;
  425. HRESULT ddrval;
  426. WORD highVidMem;
  427. WORD lowVidMem;
  428. ULONG ulMemoryOffset;
  429. ppdev = (PDEV*) lpFlip->lpDD->dhpdev;
  430. pjIoBase = ppdev->pjIoBase;
  431. // Is the current flip still in progress?
  432. //
  433. // Don't want a flip to work until after the last flip is done,
  434. // so we ask for the general flip status and ignore the vmem.
  435. ddrval = vUpdateFlipStatus32I(ppdev, 0);
  436. if ((ddrval != DD_OK) || (I32_DRAW_ENGINE_BUSY( ppdev,pjIoBase)))
  437. {
  438. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  439. return(DDHAL_DRIVER_HANDLED);
  440. }
  441. ulMemoryOffset = (ULONG)(lpFlip->lpSurfTarg->lpGbl->fpVidMem >> 2);
  442. // Make sure that the border/blanking period isn't active; wait if
  443. // it is. We could return DDERR_WASSTILLDRAWING in this case, but
  444. // that will increase the odds that we can't flip the next time:
  445. while (inVBlank(ppdev, pjIoBase))
  446. ;
  447. // Do the flip
  448. highVidMem = I32_IW(pjIoBase,CRT_OFFSET_HI) & 0xfffc | (WORD)(ulMemoryOffset >>16);
  449. lowVidMem = (WORD)(ulMemoryOffset & 0xffff);
  450. if (inVBlank( ppdev, pjIoBase))
  451. {
  452. lpFlip->ddRVal = DDERR_WASSTILLDRAWING;
  453. return DDHAL_DRIVER_HANDLED;
  454. }
  455. I32_OW_DIRECT( pjIoBase,CRT_OFFSET_HI, highVidMem);
  456. I32_OW_DIRECT( pjIoBase,CRT_OFFSET_LO, lowVidMem);
  457. // Remember where and when we were when we did the flip:
  458. EngQueryPerformanceCounter(&ppdev->flipRecord.liFlipTime);
  459. ppdev->flipRecord.bFlipFlag = TRUE;
  460. ppdev->flipRecord.bHaveEverCrossedVBlank = FALSE;
  461. ppdev->flipRecord.bWasEverInDisplay = FALSE;
  462. ppdev->flipRecord.fpFlipFrom = lpFlip->lpSurfCurr->lpGbl->fpVidMem;
  463. if( inVBlank( ppdev, pjIoBase) )
  464. {
  465. ppdev->flipRecord.wFlipScanLine = 0;
  466. }
  467. else
  468. {
  469. ppdev->flipRecord.wFlipScanLine = currentScanLine(pjIoBase);
  470. }
  471. lpFlip->ddRVal = DD_OK;
  472. return(DDHAL_DRIVER_HANDLED);
  473. }
  474. /******************************Public*Routine******************************\
  475. * DWORD DdLock32I
  476. *
  477. \**************************************************************************/
  478. DWORD DdLock32I(
  479. PDD_LOCKDATA lpLock)
  480. {
  481. PDEV* ppdev;
  482. HRESULT ddrval;
  483. ppdev = (PDEV*) lpLock->lpDD->dhpdev;
  484. // Check to see if any pending physical flip has occurred.
  485. // Don't allow a lock if a blt is in progress:
  486. ddrval = vUpdateFlipStatus32I(ppdev, lpLock->lpDDSurface->lpGbl->fpVidMem);
  487. if (ddrval != DD_OK)
  488. {
  489. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  490. return(DDHAL_DRIVER_HANDLED);
  491. }
  492. // Here's one of the places where the Windows 95 and Windows NT DirectDraw
  493. // implementations differ: on Windows NT, you should watch for
  494. // DDLOCK_WAIT and loop in the driver while the accelerator is busy.
  495. // On Windows 95, it doesn't really matter.
  496. //
  497. // (The reason is that Windows NT allows applications to draw directly
  498. // to the frame buffer even while the accelerator is running, and does
  499. // not synchronize everything on the Win16Lock. Note that on Windows NT,
  500. // it is even possible for multiple threads to be holding different
  501. // DirectDraw surface locks at the same time.)
  502. if (lpLock->dwFlags & DDLOCK_WAIT)
  503. {
  504. do {} while (I32_DRAW_ENGINE_BUSY(ppdev, ppdev->pjIoBase));
  505. }
  506. else if (I32_DRAW_ENGINE_BUSY(ppdev, ppdev->pjIoBase))
  507. {
  508. lpLock->ddRVal = DDERR_WASSTILLDRAWING;
  509. return(DDHAL_DRIVER_HANDLED);
  510. }
  511. return(DDHAL_DRIVER_NOTHANDLED);
  512. }
  513. /******************************Public*Routine******************************\
  514. * DWORD DdGetBltStatus32I
  515. *
  516. * Doesn't currently really care what surface is specified, just checks
  517. * and goes.
  518. *
  519. \**************************************************************************/
  520. DWORD DdGetBltStatus32I(
  521. PDD_GETBLTSTATUSDATA lpGetBltStatus)
  522. {
  523. PDEV* ppdev;
  524. HRESULT ddRVal;
  525. ppdev = (PDEV*) lpGetBltStatus->lpDD->dhpdev;
  526. ddRVal = DD_OK;
  527. if (lpGetBltStatus->dwFlags == DDGBS_CANBLT)
  528. {
  529. // DDGBS_CANBLT case: can we add a blt?
  530. ddRVal = vUpdateFlipStatus32I(ppdev,
  531. lpGetBltStatus->lpDDSurface->lpGbl->fpVidMem);
  532. if (ddRVal == DD_OK)
  533. {
  534. // There was no flip going on, so is there room in the FIFO
  535. // to add a blt?
  536. if (I32_FIFO_SPACE_AVAIL(ppdev,ppdev->pjIoBase,12)) // Should match DdBlt//XXX
  537. {
  538. ddRVal = DDERR_WASSTILLDRAWING;
  539. }
  540. }
  541. }
  542. else
  543. {
  544. // DDGBS_ISBLTDONE case: is a blt in progress?
  545. if (I32_DRAW_ENGINE_BUSY( ppdev,ppdev->pjIoBase))
  546. {
  547. ddRVal = DDERR_WASSTILLDRAWING;
  548. }
  549. }
  550. lpGetBltStatus->ddRVal = ddRVal;
  551. return(DDHAL_DRIVER_HANDLED);
  552. }
  553. /******************************Public*Routine******************************\
  554. * DWORD DdGetFlipStatus32I
  555. *
  556. * If the display has gone through one refresh cycle since the flip
  557. * occurred, we return DD_OK. If it has not gone through one refresh
  558. * cycle we return DDERR_WASSTILLDRAWING to indicate that this surface
  559. * is still busy "drawing" the flipped page. We also return
  560. * DDERR_WASSTILLDRAWING if the bltter is busy and the caller wanted
  561. * to know if they could flip yet.
  562. *
  563. \**************************************************************************/
  564. DWORD DdGetFlipStatus32I(
  565. PDD_GETFLIPSTATUSDATA lpGetFlipStatus)
  566. {
  567. PDEV* ppdev;
  568. ppdev = (PDEV*) lpGetFlipStatus->lpDD->dhpdev;
  569. // We don't want a flip to work until after the last flip is done,
  570. // so we ask for the general flip status and ignore the vmem:
  571. lpGetFlipStatus->ddRVal = vUpdateFlipStatus32I(ppdev, 0);
  572. // Check if the bltter is busy if someone wants to know if they can
  573. // flip:
  574. if (lpGetFlipStatus->dwFlags == DDGFS_CANFLIP)
  575. {
  576. if ((lpGetFlipStatus->ddRVal == DD_OK) && (I32_DRAW_ENGINE_BUSY( ppdev,ppdev->pjIoBase)))
  577. {
  578. lpGetFlipStatus->ddRVal = DDERR_WASSTILLDRAWING;
  579. }
  580. }
  581. return(DDHAL_DRIVER_HANDLED);
  582. }
  583. /******************************Public*Routine******************************\
  584. * DWORD DdWaitForVerticalBlank32I
  585. *
  586. \**************************************************************************/
  587. DWORD DdWaitForVerticalBlank32I(
  588. PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
  589. {
  590. PDEV* ppdev;
  591. BYTE* pjIoBase;
  592. ppdev = (PDEV*) lpWaitForVerticalBlank->lpDD->dhpdev;
  593. pjIoBase = ppdev->pjIoBase;
  594. lpWaitForVerticalBlank->ddRVal = DD_OK;
  595. switch (lpWaitForVerticalBlank->dwFlags)
  596. {
  597. case DDWAITVB_I_TESTVB:
  598. // If TESTVB, it's just a request for the current vertical blank
  599. // status:
  600. if (inVBlank( ppdev,pjIoBase))
  601. lpWaitForVerticalBlank->bIsInVB = TRUE;
  602. else
  603. lpWaitForVerticalBlank->bIsInVB = FALSE;
  604. return(DDHAL_DRIVER_HANDLED);
  605. case DDWAITVB_BLOCKBEGIN:
  606. // If BLOCKBEGIN is requested, we wait until the vertical blank
  607. // is over, and then wait for the display period to end:
  608. while (inVBlank( ppdev,pjIoBase))
  609. ;
  610. while (!inVBlank( ppdev,pjIoBase))
  611. ;
  612. return(DDHAL_DRIVER_HANDLED);
  613. case DDWAITVB_BLOCKEND:
  614. // If BLOCKEND is requested, we wait for the vblank interval to end:
  615. while (!(inVBlank( ppdev,pjIoBase)))
  616. ;
  617. while (inVBlank( ppdev,pjIoBase))
  618. ;
  619. return(DDHAL_DRIVER_HANDLED);
  620. }
  621. return(DDHAL_DRIVER_NOTHANDLED);
  622. }
  623. /******************************Public*Routine******************************\
  624. * DWORD DdGetScanLine32I
  625. *
  626. \**************************************************************************/
  627. DWORD DdGetScanLine32I(
  628. PDD_GETSCANLINEDATA lpGetScanLine)
  629. {
  630. PDEV* ppdev;
  631. BYTE* pjIoBase;
  632. ppdev = (PDEV*) lpGetScanLine->lpDD->dhpdev;
  633. pjIoBase = ppdev->pjIoBase;
  634. lpGetScanLine->dwScanLine = I32_CURRENT_VLINE(pjIoBase);
  635. lpGetScanLine->ddRVal = DD_OK;
  636. return(DDHAL_DRIVER_HANDLED);
  637. }
  638. /******************************Public*Routine******************************\
  639. * BOOL DrvGetDirectDrawInfo32I
  640. *
  641. * Will be called before DrvEnableDirectDraw is called.
  642. *
  643. \**************************************************************************/
  644. BOOL DrvGetDirectDrawInfo32I(
  645. DHPDEV dhpdev,
  646. DD_HALINFO* pHalInfo,
  647. DWORD* pdwNumHeaps,
  648. VIDEOMEMORY* pvmList, // Will be NULL on first call
  649. DWORD* pdwNumFourCC,
  650. DWORD* pdwFourCC) // Will be NULL on first call
  651. {
  652. BOOL bCanFlip;
  653. PDEV* ppdev;
  654. LONGLONG li;
  655. OH *poh;
  656. DWORD i;
  657. ppdev = (PDEV*) dhpdev;
  658. DISPDBG((10,"DrvGetDirectDrawInfo I32"));
  659. pHalInfo->dwSize = sizeof(*pHalInfo);
  660. // Current primary surface attributes:
  661. pHalInfo->vmiData.pvPrimary = ppdev->pjScreen;
  662. pHalInfo->vmiData.dwDisplayWidth = ppdev->cxScreen;
  663. pHalInfo->vmiData.dwDisplayHeight = ppdev->cyScreen;
  664. pHalInfo->vmiData.lDisplayPitch = ppdev->lDelta;
  665. pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
  666. pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB;
  667. pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = ppdev->cBitsPerPel;
  668. if (ppdev->iBitmapFormat == BMF_8BPP)
  669. {
  670. pHalInfo->vmiData.ddpfDisplay.dwFlags |= DDPF_PALETTEINDEXED8;
  671. }
  672. // These masks will be zero at 8bpp:
  673. pHalInfo->vmiData.ddpfDisplay.dwRBitMask = ppdev->flRed;
  674. pHalInfo->vmiData.ddpfDisplay.dwGBitMask = ppdev->flGreen;
  675. pHalInfo->vmiData.ddpfDisplay.dwBBitMask = ppdev->flBlue;
  676. // We can't do any accelerations on the Mach32 above 16bpp -- the only
  677. // DirectDraw support we can provide is direct frame buffer access.
  678. if (ppdev->iBitmapFormat < BMF_24BPP)
  679. {
  680. // Set up the pointer to the first available video memory after
  681. // the primary surface:
  682. bCanFlip = FALSE;
  683. // Free up as much off-screen memory as possible:
  684. bMoveAllDfbsFromOffscreenToDibs(ppdev);
  685. // Now simply reserve the biggest chunks for use by DirectDraw:
  686. poh = ppdev->pohDirectDraw;
  687. if (poh == NULL)
  688. {
  689. poh = pohAllocate(ppdev,
  690. NULL,
  691. ppdev->heap.cxMax,
  692. ppdev->heap.cyMax,
  693. FLOH_MAKE_PERMANENT);
  694. ppdev->pohDirectDraw = poh;
  695. }
  696. // this will work as is if using the NT common 2-d heap code.
  697. if (poh != NULL)
  698. {
  699. *pdwNumHeaps = 1;
  700. // Check to see if we can allocate memory to the right of the visible
  701. // surface.
  702. // Fill in the list of off-screen rectangles if we've been asked
  703. // to do so:
  704. if (pvmList != NULL)
  705. {
  706. DISPDBG((10, "DirectDraw gets %li x %li surface at (%li, %li)",
  707. poh->cx, poh->cy, poh->x, poh->y));
  708. pvmList->dwFlags = VIDMEM_ISRECTANGULAR;
  709. pvmList->fpStart = (poh->y * ppdev->lDelta)
  710. + (poh->x * ppdev->cjPelSize);
  711. pvmList->dwWidth = poh->cx * ppdev->cjPelSize;
  712. pvmList->dwHeight = poh->cy;
  713. pvmList->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  714. if ((DWORD) ppdev->cyScreen <= pvmList->dwHeight)
  715. {
  716. bCanFlip = TRUE;
  717. }
  718. DISPDBG((10,"CanFlip = %d", bCanFlip));
  719. }
  720. }
  721. pHalInfo->ddCaps.dwCaps = DDCAPS_BLT
  722. | DDCAPS_COLORKEY
  723. | DDCAPS_BLTCOLORFILL
  724. | DDCAPS_READSCANLINE;
  725. pHalInfo->ddCaps.dwCKeyCaps = 0;
  726. pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
  727. | DDSCAPS_PRIMARYSURFACE;
  728. if (bCanFlip)
  729. {
  730. pHalInfo->ddCaps.ddsCaps.dwCaps |= DDSCAPS_FLIP;
  731. }
  732. }
  733. else
  734. {
  735. pHalInfo->ddCaps.dwCaps = DDCAPS_READSCANLINE;
  736. }
  737. // dword alignment must be guaranteed for off-screen surfaces:
  738. pHalInfo->vmiData.dwOffscreenAlign = 8;
  739. DISPDBG((10,"DrvGetDirectDrawInfo exit"));
  740. return(TRUE);
  741. }