Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2214 lines
82 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ddsacc.c
  6. * Content: Direct Draw surface access support
  7. * Lock & Unlock
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 10-jan-94 craige initial implementation
  12. * 13-jan-95 craige re-worked to updated spec + ongoing work
  13. * 22-jan-95 craige made 32-bit + ongoing work
  14. * 31-jan-95 craige and even more ongoing work...
  15. * 04-feb-95 craige performance tuning, ongoing work
  16. * 27-feb-95 craige new sync. macros
  17. * 02-mar-95 craige use pitch (not stride)
  18. * 15-mar-95 craige HEL
  19. * 19-mar-95 craige use HRESULTs
  20. * 20-mar-95 craige validate locking rectangle
  21. * 01-apr-95 craige happy fun joy updated header file
  22. * 07-apr-95 craige bug 2 - unlock should accept the screen ptr
  23. * take/release Win16Lock when access GDI's surface
  24. * 09-apr-95 craige maintain owner of Win16Lock so we can release it
  25. * if someone forgets; remove locks from dead processes
  26. * 12-apr-95 craige don't use GETCURRPID; fixed Win16 lock deadlock
  27. * condition
  28. * 06-may-95 craige use driver-level csects only
  29. * 12-jun-95 craige new process list stuff
  30. * 18-jun-95 craige allow duplicate surfaces
  31. * 25-jun-95 craige one ddraw mutex; hold DDRAW lock when locking primary
  32. * 26-jun-95 craige reorganized surface structure
  33. * 28-jun-95 craige ENTER_DDRAW at very start of fns
  34. * 03-jul-95 craige YEEHAW: new driver struct; SEH
  35. * 07-jul-95 craige added test for BUSY
  36. * 08-jul-95 craige take Win16 lock always on surface lock
  37. * 09-jul-95 craige win16 lock re-entrant, so count it!
  38. * 11-jul-95 craige set busy bit when taking win16 lock to avoid GDI from
  39. * drawing on the display.
  40. * 13-jul-95 craige ENTER_DDRAW is now the win16 lock
  41. * 16-jul-95 craige check DDRAWISURF_HELCB
  42. * 31-jul-95 craige don't return error from HAL unlock if not handled;
  43. * validate flags
  44. * 01-aug-95 craig use bts for setting & testing BUSY bit
  45. * 04-aug-95 craige added InternalLock/Unlock
  46. * 10-aug-95 toddla added DDLOCK_WAIT flag
  47. * 12-aug-95 craige bug 488: need to call tryDoneLock even after HAL call
  48. * to Unlock
  49. * 18-aug-95 toddla DDLOCK_READONLY and DDLOCK_WRITEONLY
  50. * 27-aug-95 craige bug 723 - treat vram & sysmem the same when locking
  51. * 09-dec-95 colinmc Added execute buffer support
  52. * 11-dec-95 colinmc Added lightweight(-ish) Lock and Unlock for use by
  53. * Direct3D (exported as private DLL API).
  54. * 02-jan-96 kylej handle new interface structs.
  55. * 26-jan-96 jeffno Lock/Unlock no longer special-case whole surface...
  56. * You need to record what ptr was given to user since
  57. * it will not be same as kernel-mode ptr
  58. * 01-feb-96 colinmc Fixed nasty bug causing Win16 lock to be released
  59. * on surfaces explicitly created in system memory
  60. * which did not take the lock in the first place
  61. * 12-feb-96 colinmc Surface lost flag moved from global to local object
  62. * 13-mar-96 jeffno Do not allow lock on an NT emulated primary!
  63. * 18-apr-96 kylej Bug 18546: Take bytes per pixel into account when
  64. * calculating lock offset.
  65. * 20-apr-96 kylej Bug 15268: exclude the cursor when a primary
  66. * surface rect is locked.
  67. * 01-may-96 colinmc Bug 20005: InternalLock does not check for lost
  68. * surfaces
  69. * 17-may-96 mdm Bug 21499: perf problems with new InternalLock
  70. * 14-jun-96 kylej NT Bug 38227: Added DDLOCK_FAILONVISRGNCHANGED so
  71. * that InternalLock() can fail if the vis rgn is not
  72. * current. This flag is only used on NT.
  73. * 05-jul-96 colinmc Work Item: Remove requirement on taking Win16 lock
  74. * for VRAM surfaces (not primary)
  75. * 10-oct-96 colinmc Refinements of the Win16 locking stuff
  76. * 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
  77. * memory usage
  78. * 01-feb-97 colinmc Bug 5457: Fixed Win16 lock problem causing hang
  79. * with mutliple AMovie instances on old cards
  80. * 11-mar-97 jeffno Asynchronous DMA support
  81. * 23-mar-97 colinmc Hold Win16 lock for AGP surfaces for now
  82. * 24-mar-97 jeffno Optimized Surfaces
  83. * 03-oct-97 jeffno DDSCAPS2 and DDSURFACEDESC2
  84. * 19-dec-97 jvanaken IDDS4::Unlock now takes pointer to rectangle.
  85. *
  86. ***************************************************************************/
  87. #include "ddrawpr.h"
  88. #ifdef WINNT
  89. #include "ddrawgdi.h"
  90. #endif
  91. /*
  92. * Bit number of the VRAM flag in the PDEVICE dwFlags field.
  93. */
  94. #define VRAM_BIT 15
  95. /* doneBusyWin16Lock releases the win16 lock and busy bit. It is used
  96. * in lock routines for failure cases in which we have not yet
  97. * incremented the win16 lock or taken the DD critical section a
  98. * second time. It is also called by tryDoneLock. */
  99. static void doneBusyWin16Lock( LPDDRAWI_DIRECTDRAW_GBL pdrv )
  100. {
  101. #ifdef WIN95
  102. if( pdrv->dwWin16LockCnt == 0 )
  103. {
  104. *(pdrv->lpwPDeviceFlags) &= ~BUSY;
  105. }
  106. #ifdef WIN16_SEPARATE
  107. LEAVE_WIN16LOCK();
  108. #endif
  109. #endif
  110. } /* doneBusyWin16Lock */
  111. /* tryDoneLock releases the win16 lock and busy bit. It is used in
  112. * unlock routines since it decrements the Win16 count in addition to
  113. * releasing the lock. WARNING: This function does nothing and
  114. * returns no error if the win16 lock is not owned by the current DD
  115. * object. This will result in the lock being held and will probably
  116. * bring the machine to its knees. */
  117. static void tryDoneLock( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, DWORD pid )
  118. {
  119. LPDDRAWI_DIRECTDRAW_GBL pdrv = pdrv_lcl->lpGbl;
  120. if( pdrv->dwWin16LockCnt == 0 )
  121. {
  122. return;
  123. }
  124. pdrv->dwWin16LockCnt--;
  125. doneBusyWin16Lock( pdrv );
  126. LEAVE_DDRAW();
  127. } /* tryDoneLock */
  128. #ifdef USE_ALIAS
  129. /*
  130. * Undo an aliased lock.
  131. *
  132. * An aliased lock is one which required the PDEVICE VRAM bit
  133. * to be cleared to prevent the accelerator touching memory
  134. * at the same time as the locked surface.
  135. *
  136. * NOTE: The lock does not necessarily have to be on a VRAM
  137. * surface. Locks of implicit system memory surfaces also
  138. * clear the VRAM bit (to ensure similar behaviour for
  139. * system and video memory surfaces).
  140. */
  141. static void undoAliasedLock( LPDDRAWI_DIRECTDRAW_GBL pdrv )
  142. {
  143. DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
  144. #ifdef WIN16_SEPARATE
  145. ENTER_WIN16LOCK();
  146. #endif
  147. pdrv->dwAliasedLockCnt--;
  148. if( 0UL == pdrv->dwAliasedLockCnt )
  149. {
  150. /*
  151. * That was the last outstanding aliased lock on this
  152. * device so put the VRAM bit in the PDEVICE back the
  153. * way it was.
  154. */
  155. if( pdrv->dwFlags & DDRAWI_PDEVICEVRAMBITCLEARED )
  156. {
  157. /*
  158. * The VRAM bit was set when we took the first lock so
  159. * we had to clear it. We must now set it again.
  160. */
  161. DPF( 4, "PDevice was VRAM - restoring VRAM bit", pdrv );
  162. *(pdrv->lpwPDeviceFlags) |= VRAM;
  163. pdrv->dwFlags &= ~DDRAWI_PDEVICEVRAMBITCLEARED;
  164. }
  165. }
  166. #ifdef WIN16_SEPARATE
  167. LEAVE_WIN16LOCK();
  168. #endif
  169. }
  170. #endif /* USE_ALIAS */
  171. #ifdef WIN95
  172. #define DONE_LOCK_EXCLUDE() \
  173. if( this_lcl->dwFlags & DDRAWISURF_LOCKEXCLUDEDCURSOR ) \
  174. { \
  175. DD16_Unexclude(pdrv->dwPDevice); \
  176. this_lcl->dwFlags &= ~DDRAWISURF_LOCKEXCLUDEDCURSOR; \
  177. }
  178. #else
  179. #define DONE_LOCK_EXCLUDE() ;
  180. #endif
  181. /*
  182. * The following two routines are used by D3D on NT to manipulate
  183. * the DDraw mutex exclusion mechanism
  184. */
  185. void WINAPI AcquireDDThreadLock(void)
  186. {
  187. ENTER_DDRAW();
  188. }
  189. void WINAPI ReleaseDDThreadLock(void)
  190. {
  191. LEAVE_DDRAW();
  192. }
  193. HRESULT WINAPI DDInternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID* lpBits )
  194. {
  195. return InternalLock(this_lcl, lpBits, NULL, DDLOCK_TAKE_WIN16_VRAM |
  196. DDLOCK_FAILLOSTSURFACES);
  197. }
  198. HRESULT WINAPI DDInternalUnlock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl )
  199. {
  200. BUMP_SURFACE_STAMP(this_lcl->lpGbl);
  201. return InternalUnlock(this_lcl, NULL, NULL, DDLOCK_TAKE_WIN16_VRAM);
  202. }
  203. #define DPF_MODNAME "InternalLock"
  204. #if !defined( WIN16_SEPARATE) || defined(WINNT)
  205. #pragma message(REMIND("InternalLock not tested without WIN16_SEPARATE."))
  206. #endif // WIN16_SEPARATE
  207. /*
  208. * InternalLock provides the basics of locking for trusted clients.
  209. * No parameter validation is done and no ddsd is filled in. The
  210. * client promises the surface is not lost and is otherwise well
  211. * constructed. If caller does not pass DDLOCK_TAKE_WIN16 in dwFlags,
  212. * we assume the DDraw critical section, Win16 lock, and busy bit are
  213. * already entered/set. If caller does pass DDLOCK_TAKE_WIN16,
  214. * InternalLock will do so if needed. Note that passing
  215. * DDLOCK_TAKE_WIN16 does not necessarily result in the Win16 lock
  216. * being taken. It is only taken if needed.
  217. */
  218. HRESULT InternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID *pbits,
  219. LPRECT lpDestRect, DWORD dwFlags )
  220. {
  221. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  222. LPDDRAWI_DIRECTDRAW_GBL pdrv;
  223. DWORD this_lcl_caps;
  224. LPDDRAWI_DDRAWSURFACE_GBL this;
  225. DWORD rc;
  226. DDHAL_LOCKDATA ld;
  227. LPDDHALSURFCB_LOCK lhalfn;
  228. LPDDHALSURFCB_LOCK lfn;
  229. BOOL emulation;
  230. LPACCESSRECTLIST parl;
  231. LPWORD pdflags = NULL;
  232. BOOL isvramlock = FALSE;
  233. #ifdef USE_ALIAS
  234. BOOL holdwin16lock;
  235. #endif /* USE_ALIAS */
  236. FLATPTR OldfpVidMem; //Used to detect if driver moved surface on Lock call
  237. this = this_lcl->lpGbl;
  238. this_lcl_caps = this_lcl->ddsCaps.dwCaps;
  239. pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
  240. pdrv = pdrv_lcl->lpGbl;
  241. #ifdef WINNT
  242. // Update DDraw handle in driver GBL object.
  243. pdrv->hDD = pdrv_lcl->hDD;
  244. #endif
  245. ENTER_DDRAW();
  246. /*
  247. * If the surface was involved in a hardware op, we need to
  248. * probe the driver to see if it's done. NOTE this assumes
  249. * that only one driver can be responsible for a system memory
  250. * operation.
  251. * This operation is done at the API level Lock since the situation we
  252. * need to avoid is the CPU and the DMA/Busmaster hitting a surface
  253. * at the same time. We can trust the HAL driver to know it should not
  254. * try to DMA out of the same surface twice. This is almost certainly
  255. * enforced anyway by the likelihood that the hardware will have only
  256. * one context with which to perform the transfer: it has to wait.
  257. */
  258. if( this->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED )
  259. {
  260. WaitForDriverToFinishWithSurface(this_lcl->lpSurfMore->lpDD_lcl, this_lcl);
  261. }
  262. // The following code was added to keep all of the HALs from
  263. // changing their Lock() code when they add video port support.
  264. // If the video port was using this surface but was recently
  265. // flipped, we will make sure that the flip actually occurred
  266. // before allowing access. This allows double buffered capture
  267. // w/o tearing.
  268. // ScottM 7/10/96
  269. if( this_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT )
  270. {
  271. LPDDRAWI_DDVIDEOPORT_INT lpVideoPort;
  272. LPDDRAWI_DDVIDEOPORT_LCL lpVideoPort_lcl;
  273. // Look at all video ports to see if any of them recently
  274. // flipped from this surface.
  275. lpVideoPort = pdrv->dvpList;
  276. while( NULL != lpVideoPort )
  277. {
  278. lpVideoPort_lcl = lpVideoPort->lpLcl;
  279. if( lpVideoPort_lcl->fpLastFlip == this->fpVidMem )
  280. {
  281. // This can potentially tear - check the flip status
  282. LPDDHALVPORTCB_GETFLIPSTATUS pfn;
  283. DDHAL_GETVPORTFLIPSTATUSDATA GetFlipData;
  284. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  285. pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
  286. pfn = pdrv_lcl->lpDDCB->HALDDVideoPort.GetVideoPortFlipStatus;
  287. if( pfn != NULL ) // Will simply tear if function not supproted
  288. {
  289. GetFlipData.lpDD = pdrv_lcl;
  290. GetFlipData.fpSurface = this->fpVidMem;
  291. KeepTrying:
  292. rc = DDHAL_DRIVER_NOTHANDLED;
  293. DOHALCALL( GetVideoPortFlipStatus, pfn, GetFlipData, rc, 0 );
  294. if( ( DDHAL_DRIVER_HANDLED == rc ) &&
  295. ( DDERR_WASSTILLDRAWING == GetFlipData.ddRVal ) )
  296. {
  297. if( dwFlags & DDLOCK_WAIT)
  298. {
  299. goto KeepTrying;
  300. }
  301. LEAVE_DDRAW();
  302. return DDERR_WASSTILLDRAWING;
  303. }
  304. }
  305. }
  306. lpVideoPort = lpVideoPort->lpLink;
  307. }
  308. }
  309. // Check for VRAM access - if yes, we need to take the win16 lock
  310. // and the busy bit. From the user API, we treat the vram and
  311. // implicit sysmemory cases the same because many developers were
  312. // treating them differently and then breaking when they actually
  313. // got vram. Also, we only bother with this if the busy bit (and
  314. // Win16 lock) are currently available.
  315. /*
  316. * NOTE: The semantics are that for each VRAM (or simulated VRAM lock)
  317. * the Win16 lock and BUSY bit are held until we have called the
  318. * driver and are sure we can do an aliased lock (in which case we
  319. * release them). Otherwise, we keep holding them.
  320. *
  321. * IMPORTANT NOTE: Behaviour change. Previously we did not perform
  322. * the Win16 locking actions if this was not the first lock of this
  323. * surface. This no longer works as we can no longer ensure all the
  324. * necessary locking actions will happen on the first lock of the
  325. * surface. For example, the first lock on the surface may be
  326. * aliasable so we don't set the busy bit. A subsequent lock may
  327. * not be aliasable, however, so we need to take the lock on that
  328. * occassion. This should not, however, be much of a hit as the
  329. * really expensive actions only take place on the first
  330. * Win16 lock (0UL == pdrv->dwWin16LockCnt) so once someone has
  331. * taken the Win16 lock remaining locks should be cheap. Also,
  332. * multiple locks are unusual so, all in all, this should be pretty
  333. * low risk.
  334. */
  335. FlushD3DStates(this_lcl);
  336. #if COLLECTSTATS
  337. if(this_lcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
  338. ++this_lcl->lpSurfMore->lpDD_lcl->dwNumTexLocks;
  339. #endif
  340. if( ( ((dwFlags & DDLOCK_TAKE_WIN16) && !(this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED)) ||
  341. ((dwFlags & DDLOCK_TAKE_WIN16_VRAM) && (this_lcl_caps & DDSCAPS_VIDEOMEMORY)) )
  342. && (pdrv->dwFlags & DDRAWI_DISPLAYDRV) )
  343. {
  344. DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
  345. !(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
  346. DPF( 5, "Performing VRAM style lock for surface 0x%08x", this_lcl );
  347. /*
  348. * Lock of a VRAM surface (or a surface being treated like a VRAM surface)
  349. * with no outstanding locks pending. Take the Win16 lock.
  350. */
  351. isvramlock = TRUE;
  352. #ifdef WIN95
  353. // Don't worry about the busy bit for NT
  354. /*
  355. * We always take the Win16 lock while we mess with the driver's
  356. * busy bits. However, if we have a surface with an alias we
  357. * will release the Win16 lock before we exit this function.
  358. */
  359. #ifdef WIN16_SEPARATE
  360. ENTER_WIN16LOCK();
  361. #endif // WIN16_SEPARATE
  362. // If dwWin16LockCnt > 0 then we already set the busy bit, so
  363. // don't bother doing it again. NOTE: this assumption may be
  364. // limiting.
  365. if( 0UL == pdrv->dwWin16LockCnt )
  366. {
  367. BOOL isbusy;
  368. pdflags = pdrv->lpwPDeviceFlags;
  369. isbusy = 0;
  370. _asm
  371. {
  372. mov eax, pdflags
  373. bts word ptr [eax], BUSY_BIT
  374. adc isbusy,0
  375. }
  376. if( isbusy )
  377. {
  378. DPF( 2, "BUSY - Lock, dwWin16LockCnt = %ld, %04x, %04x (%ld)",
  379. pdrv->dwWin16LockCnt, *pdflags, BUSY, BUSY_BIT );
  380. #ifdef WIN16_SEPARATE
  381. LEAVE_WIN16LOCK();
  382. #endif // WIN16_SEPARATE
  383. LEAVE_DDRAW();
  384. return DDERR_SURFACEBUSY;
  385. } // isbusy
  386. } // ( 0UL == pdrv->dwWin16LockCnt )
  387. #endif // WIN95
  388. } // VRAM locking actions (Win16 lock, busy bit).
  389. // If we have been asked to check for lost surfaces do it NOW after
  390. // the Win16 locking code. This is essential as otherwise we may
  391. // lose the surface after the check but before we actually get round
  392. // to doing anything with the surface
  393. if( ( dwFlags & DDLOCK_FAILLOSTSURFACES ) && SURFACE_LOST( this_lcl ) )
  394. {
  395. DPF_ERR( "Surface is lost - can't lock" );
  396. #if defined( WIN16_SEPARATE) && !defined(WINNT)
  397. if( isvramlock )
  398. doneBusyWin16Lock( pdrv );
  399. #endif
  400. LEAVE_DDRAW();
  401. return DDERR_SURFACELOST;
  402. }
  403. // Make sure someone else has not already locked the part of the
  404. // surface we want. We don't need to worry about this for DX8
  405. // resource management. In fact, for vertex buffers, the following
  406. // code doesn't work because the Rect is actually a linear range.
  407. if(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
  408. !(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
  409. {
  410. BOOL hit = FALSE;
  411. if( lpDestRect != NULL )
  412. {
  413. // Caller has asked to lock a subsection of the surface.
  414. parl = this->lpRectList;
  415. // Run through all rectangles, looking for an intersection.
  416. while( parl != NULL )
  417. {
  418. RECT res;
  419. if( IntersectRect( &res, lpDestRect, &parl->rDest ) )
  420. {
  421. hit = TRUE;
  422. break;
  423. }
  424. parl = parl->lpLink;
  425. }
  426. }
  427. // Either (our rect overlaps with someone else's rect), or
  428. // (someone else has locked the entire surface), or
  429. // (someone locked part of the surface but we want to lock the whole thing).
  430. if( hit ||
  431. (this->lpRectList == NULL && this->dwUsageCount > 0) ||
  432. ((lpDestRect == NULL) && ((this->dwUsageCount > 0) || (this->lpRectList != NULL))) )
  433. {
  434. DPF(2,"Surface is busy: parl=0x%x, lpDestRect=0x%x, "
  435. "this->dwUsageCount=0x%x, this->lpRectList=0x%x, hit=%d",
  436. parl,lpDestRect,this->dwUsageCount,this->lpRectList,hit );
  437. #if defined( WIN16_SEPARATE) && !defined(WINNT)
  438. if( isvramlock )
  439. {
  440. doneBusyWin16Lock( pdrv );
  441. }
  442. #endif
  443. LEAVE_DDRAW();
  444. return DDERR_SURFACEBUSY;
  445. }
  446. // Create a rectangle access list member. Note that for
  447. // performance, we don't do this on 95 if the user is locking
  448. // the whole surface.
  449. parl = NULL;
  450. if(lpDestRect)
  451. {
  452. parl = MemAlloc( sizeof( ACCESSRECTLIST ) );
  453. if( parl == NULL )
  454. {
  455. #if defined( WIN16_SEPARATE) && !defined(WINNT)
  456. if( isvramlock )
  457. {
  458. doneBusyWin16Lock( pdrv );
  459. }
  460. #endif
  461. DPF(0,"InternalLock: Out of memory.");
  462. LEAVE_DDRAW();
  463. return DDERR_OUTOFMEMORY;
  464. }
  465. if(lpDestRect != NULL)
  466. {
  467. parl->lpLink = this->lpRectList;
  468. parl->rDest = *lpDestRect;
  469. }
  470. else
  471. {
  472. parl->lpLink = NULL;
  473. parl->rDest.top = 0;
  474. parl->rDest.left = 0;
  475. parl->rDest.bottom = (int) (DWORD) this->wHeight;
  476. parl->rDest.right = (int) (DWORD) this->wWidth;
  477. }
  478. parl->lpOwner = pdrv_lcl;
  479. #ifdef USE_ALIAS
  480. parl->dwFlags = 0UL;
  481. parl->lpHeapAliasInfo = NULL;
  482. #endif /* USE_ALIAS */
  483. this->lpRectList = parl;
  484. //parl->lpSurfaceData is filled below, after HAL call
  485. /*
  486. * Add a rect to the region list if this is a managed surface and not a read only lock
  487. */
  488. if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
  489. {
  490. LPREGIONLIST lpRegionList = this_lcl->lpSurfMore->lpRegionList;
  491. if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
  492. {
  493. lpRegionList->rect[(lpRegionList->rdh.nCount)++] = *((LPRECTL)lpDestRect);
  494. lpRegionList->rdh.nRgnSize += sizeof(RECT);
  495. if((lpDestRect->left & 0xffff) < lpRegionList->rdh.rcBound.left)
  496. lpRegionList->rdh.rcBound.left = lpDestRect->left & 0xffff;
  497. if((lpDestRect->right & 0xfff)> lpRegionList->rdh.rcBound.right)
  498. lpRegionList->rdh.rcBound.right = lpDestRect->right & 0xffff;
  499. if(lpDestRect->top < lpRegionList->rdh.rcBound.top)
  500. lpRegionList->rdh.rcBound.top = lpDestRect->top;
  501. if(lpDestRect->bottom > lpRegionList->rdh.rcBound.bottom)
  502. lpRegionList->rdh.rcBound.bottom = lpDestRect->bottom;
  503. }
  504. }
  505. }
  506. else
  507. {
  508. /*
  509. * We are locking the whole surface, so by setting nCount to the
  510. * max number of dirty rects allowed, we will force the cache
  511. * manager to update the entire surface
  512. */
  513. if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
  514. {
  515. this_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
  516. }
  517. }
  518. }
  519. else
  520. {
  521. parl = NULL;
  522. DDASSERT(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8);
  523. DDASSERT(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE);
  524. }
  525. // Increment the usage count of this surface.
  526. this->dwUsageCount++;
  527. CHANGE_GLOBAL_CNT( pdrv, this, 1 );
  528. // Is this an emulation surface or driver surface?
  529. //
  530. // NOTE: There are different HAL entry points for execute buffers
  531. // and conventional surfaces.
  532. if( (this_lcl_caps & DDSCAPS_SYSTEMMEMORY) ||
  533. (this_lcl->dwFlags & DDRAWISURF_HELCB) )
  534. {
  535. if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
  536. lfn = pdrv_lcl->lpDDCB->HELDDExeBuf.LockExecuteBuffer;
  537. else
  538. lfn = pdrv_lcl->lpDDCB->HELDDSurface.Lock;
  539. lhalfn = lfn;
  540. emulation = TRUE;
  541. }
  542. else
  543. {
  544. if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
  545. {
  546. lfn = pdrv_lcl->lpDDCB->HALDDExeBuf.LockExecuteBuffer;
  547. lhalfn = pdrv_lcl->lpDDCB->cbDDExeBufCallbacks.LockExecuteBuffer;
  548. }
  549. else
  550. {
  551. lfn = pdrv_lcl->lpDDCB->HALDDSurface.Lock;
  552. lhalfn = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Lock;
  553. }
  554. emulation = FALSE;
  555. }
  556. #ifdef WIN95
  557. /*
  558. * exclude the mouse cursor if this is the display driver
  559. * and we are locking a rect on the primary surface.
  560. * and the driver is not using a HW cursor
  561. */
  562. if ( (pdrv->dwFlags & DDRAWI_DISPLAYDRV) && pdrv->dwPDevice &&
  563. (this_lcl_caps & DDSCAPS_PRIMARYSURFACE) && lpDestRect &&
  564. !(*pdrv->lpwPDeviceFlags & HARDWARECURSOR))
  565. {
  566. DD16_Exclude(pdrv->dwPDevice, (RECTL *)lpDestRect);
  567. this_lcl->dwFlags |= DDRAWISURF_LOCKEXCLUDEDCURSOR;
  568. }
  569. #endif
  570. //Remember the old fpVidMem in case the driver changes is
  571. OldfpVidMem = this->fpVidMem;
  572. // See if the driver wants to say something...
  573. rc = DDHAL_DRIVER_NOTHANDLED;
  574. if( lhalfn != NULL )
  575. {
  576. DPF(4,"InternalLock: Calling driver Lock.");
  577. ld.Lock = lhalfn;
  578. ld.lpDD = pdrv;
  579. ld.lpDDSurface = this_lcl;
  580. #ifdef WIN95
  581. ld.dwFlags = dwFlags;
  582. #else
  583. #pragma message(REMIND("So far the s3 driver will only succeed if flags==0"))
  584. ld.dwFlags = dwFlags & (DDLOCK_NOOVERWRITE | DDLOCK_READONLY | DDLOCK_WRITEONLY | DDLOCK_NOSYSLOCK | DDLOCK_DISCARDCONTENTS);
  585. #endif
  586. if( lpDestRect != NULL )
  587. {
  588. ld.bHasRect = TRUE;
  589. ld.rArea = *(LPRECTL)lpDestRect;
  590. }
  591. else
  592. {
  593. ld.bHasRect = FALSE;
  594. }
  595. try_again:
  596. #ifdef WINNT
  597. do
  598. {
  599. if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
  600. {
  601. DOHALCALL( LockExecuteBuffer, lfn, ld, rc, emulation );
  602. }
  603. else
  604. {
  605. DOHALCALL( Lock, lfn, ld, rc, emulation );
  606. if ( (dwFlags & DDLOCK_FAILONVISRGNCHANGED) ||
  607. !(rc == DDHAL_DRIVER_HANDLED && ld.ddRVal == DDERR_VISRGNCHANGED) )
  608. break;
  609. DPF(4,"Resetting VisRgn for surface %x", this_lcl);
  610. DdResetVisrgn(this_lcl, (HWND)0);
  611. }
  612. }
  613. while (rc == DDHAL_DRIVER_HANDLED && ld.ddRVal == DDERR_VISRGNCHANGED);
  614. #else
  615. if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
  616. {
  617. DOHALCALL( LockExecuteBuffer, lfn, ld, rc, emulation );
  618. }
  619. else
  620. {
  621. DOHALCALL( Lock, lfn, ld, rc, emulation );
  622. }
  623. #endif
  624. }
  625. if( rc == DDHAL_DRIVER_HANDLED )
  626. {
  627. if( ld.ddRVal == DD_OK )
  628. {
  629. DPF(5,"lpsurfdata is %08x",ld.lpSurfData);
  630. #ifdef WINNT
  631. if ( (ld.lpSurfData == (void*) ULongToPtr(0xffbadbad)) && (dwFlags & DDLOCK_FAILEMULATEDNTPRIMARY) )
  632. {
  633. ld.ddRVal = DDERR_CANTLOCKSURFACE;
  634. }
  635. #endif
  636. *pbits = ld.lpSurfData;
  637. }
  638. else if( (dwFlags & DDLOCK_WAIT) && ld.ddRVal == DDERR_WASSTILLDRAWING )
  639. {
  640. DPF(4, "Waiting...");
  641. goto try_again;
  642. }
  643. if (ld.ddRVal != DD_OK)
  644. {
  645. // Failed!
  646. #ifdef DEBUG
  647. if( (ld.ddRVal != DDERR_WASSTILLDRAWING) && (ld.ddRVal != DDERR_SURFACELOST) )
  648. {
  649. DPF( 0, "Driver failed Lock request: %ld", ld.ddRVal );
  650. }
  651. #endif
  652. // Unlink the rect list item.
  653. if(parl)
  654. {
  655. this->lpRectList = parl->lpLink;
  656. MemFree( parl );
  657. }
  658. // Now unlock the surface and bail.
  659. this->dwUsageCount--;
  660. CHANGE_GLOBAL_CNT( pdrv, this, -1 );
  661. #if defined( WIN16_SEPARATE) && !defined(WINNT)
  662. if( isvramlock )
  663. {
  664. doneBusyWin16Lock( pdrv );
  665. }
  666. #endif
  667. DONE_LOCK_EXCLUDE();
  668. LEAVE_DDRAW();
  669. return ld.ddRVal;
  670. } // ld.ddRVal
  671. }
  672. else // DDHAL_DRIVER_HANDLED
  673. {
  674. #ifdef WINNT
  675. // If the driver fails the lock, we can't allow the app to scribble with
  676. // who knows what fpVidMem...
  677. *pbits = (LPVOID) ULongToPtr(0x80000000); // Illegal for user-mode, as is anything higher.
  678. DPF_ERR("Driver did not handle Lock call. App may Access Violate");
  679. // Unlink the rect list item.
  680. if( parl )
  681. {
  682. this->lpRectList = parl->lpLink;
  683. MemFree( parl );
  684. }
  685. // Now unlock the surface and bail.
  686. this->dwUsageCount--;
  687. CHANGE_GLOBAL_CNT( pdrv, this, -1 );
  688. DONE_LOCK_EXCLUDE();
  689. LEAVE_DDRAW();
  690. return DDERR_SURFACEBUSY; //GEE: Strange error to use, but most appropriate
  691. #else // WIN95
  692. DPF(4,"Driver did not handle Lock call. Figure something out.");
  693. // Get a pointer to the surface bits.
  694. if( this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE )
  695. {
  696. *pbits = (LPVOID) pdrv->vmiData.fpPrimary;
  697. }
  698. else
  699. {
  700. *pbits = (LPVOID) this->fpVidMem;
  701. }
  702. if( ld.bHasRect)
  703. {
  704. DWORD bpp;
  705. DWORD byte_offset;
  706. DWORD left = (DWORD) ld.rArea.left;
  707. // Make the surface pointer point to the first byte of the requested rectangle.
  708. if( ld.lpDDSurface->dwFlags & DDRAWISURF_HASPIXELFORMAT )
  709. {
  710. bpp = ld.lpDDSurface->lpGbl->ddpfSurface.dwRGBBitCount;
  711. }
  712. else
  713. {
  714. bpp = ld.lpDD->vmiData.ddpfDisplay.dwRGBBitCount;
  715. }
  716. if (ld.lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
  717. {
  718. left &= 0xffff;
  719. }
  720. switch(bpp)
  721. {
  722. case 1: byte_offset = left>>3; break;
  723. case 2: byte_offset = left>>2; break;
  724. case 4: byte_offset = left>>1; break;
  725. case 8: byte_offset = left; break;
  726. case 16: byte_offset = left*2; break;
  727. case 24: byte_offset = left *3; break;
  728. case 32: byte_offset = left *4; break;
  729. }
  730. *pbits = (LPVOID) ((DWORD)*pbits +
  731. (DWORD)ld.rArea.top * ld.lpDDSurface->lpGbl->lPitch +
  732. byte_offset);
  733. if (ld.lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
  734. {
  735. ((BYTE*)*pbits) += (ld.rArea.left >> 16) * ld.lpDDSurface->lpGbl->lSlicePitch;
  736. }
  737. }
  738. #endif // WIN95
  739. } // !DDHAL_DRIVER_HANDLED
  740. if(!(dwFlags & DDLOCK_READONLY) && IsD3DManaged(this_lcl))
  741. MarkDirty(this_lcl);
  742. // Filled in, as promised above.
  743. if(parl)
  744. {
  745. parl->lpSurfaceData = *pbits;
  746. }
  747. //
  748. // At this point we are committed to the lock.
  749. //
  750. // stay holding the lock if needed
  751. if( isvramlock )
  752. {
  753. #ifdef USE_ALIAS
  754. LPHEAPALIASINFO pheapaliasinfo;
  755. pheapaliasinfo = NULL;
  756. holdwin16lock = TRUE;
  757. #ifdef DEBUG
  758. /*
  759. * Force or disable the Win16 locking behaviour
  760. * dependent on the registry settings.
  761. */
  762. if( dwRegFlags & DDRAW_REGFLAGS_DISABLENOSYSLOCK )
  763. dwFlags &= ~DDLOCK_NOSYSLOCK;
  764. if( dwRegFlags & DDRAW_REGFLAGS_FORCENOSYSLOCK )
  765. dwFlags |= DDLOCK_NOSYSLOCK;
  766. #endif /* DEBUG */
  767. #endif
  768. DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
  769. !(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
  770. if( dwFlags & DDLOCK_NOSYSLOCK )
  771. {
  772. #ifdef WINNT
  773. if( NULL != parl )
  774. parl->dwFlags |= ACCESSRECT_NOTHOLDINGWIN16LOCK;
  775. else
  776. this->dwGlobalFlags |= DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK;
  777. LEAVE_DDRAW();
  778. }
  779. else
  780. #endif /* WINNT */
  781. #ifdef USE_ALIAS
  782. /*
  783. * Remember that this was a VRAM style lock (need this when cleaning
  784. * up).
  785. */
  786. if( NULL != parl )
  787. parl->dwFlags |= ACCESSRECT_VRAMSTYLE;
  788. else
  789. this->dwGlobalFlags |= DDRAWISURFGBL_LOCKVRAMSTYLE;
  790. /*
  791. * At this point we have a pointer to the non-aliased video memory which was
  792. * either returned to us by the driver or which we computed ourselves. In
  793. * either case, if this is a video memory style lock on a surface that is
  794. * aliasable and the pointer computed lies in the range of one our aliased
  795. * video memory heaps we wish to use that pointer instead of the real video
  796. * memory pointer.
  797. */
  798. if( ( this_lcl_caps & DDSCAPS_PRIMARYSURFACE ) )
  799. {
  800. /*
  801. * If we have a primary surface we need to hold the Win16 lock even
  802. * though we have aliases. This is to prevent USER
  803. * from coming in and changing clip lists or drawing all over our locked
  804. * data.
  805. */
  806. DPF( 2, "Surface is primary. Holding the Win16 lock" );
  807. }
  808. else
  809. {
  810. if( pdrv->dwFlags & DDRAWI_NEEDSWIN16FORVRAMLOCK )
  811. {
  812. /*
  813. * For some reason this device needs the Win16 lock for VRAM surface
  814. * locking. This is probably because its bankswitched or we have a
  815. * DIB engine we don't understand.
  816. */
  817. DPF( 2, "Device needs to hold Win16 lock for VRAM surface locks" );
  818. }
  819. else
  820. {
  821. if( NULL == pdrv->phaiHeapAliases )
  822. {
  823. /*
  824. * We don't have any heaps aliases but we are not a device which
  825. * needs the Win16 lock. This means we must be an emulation or
  826. * ModeX device. In which case we don't need to hold the Win16
  827. * lock for the duration.
  828. */
  829. DDASSERT( ( pdrv->dwFlags & DDRAWI_NOHARDWARE ) || ( pdrv->dwFlags & DDRAWI_MODEX ) );
  830. DPF( 2, "Emulation or ModeX device. No need to hold Win16 lock" );
  831. holdwin16lock = FALSE;
  832. }
  833. else
  834. {
  835. if( this_lcl_caps & DDSCAPS_SYSTEMMEMORY )
  836. {
  837. /*
  838. * If the surface is an implicit system memory surface then we
  839. * take aliased style actions but we don't actually compute an alias.
  840. */
  841. holdwin16lock = FALSE;
  842. }
  843. else
  844. {
  845. FLATPTR paliasbits;
  846. LPDDRAWI_DDRAWSURFACE_GBL_MORE lpGblMore;
  847. DDASSERT( this_lcl_caps & DDSCAPS_VIDEOMEMORY );
  848. lpGblMore = GET_LPDDRAWSURFACE_GBL_MORE( this );
  849. // We use the cached alias if available and valid. We determine validity by comparing
  850. // *pbits with the original fpVidMem that was used to compute the alias. If they match
  851. // then it is safe to use the pointer.
  852. // The reason we need to do this is that the driver can change the fpVidMem of the surface.
  853. // This change can occur during any Lock calls or (in case of D3D Vertex / Command buffers)
  854. // outside of lock (during DrawPrimitives2 DDI call). Thus we need to make sure the surface
  855. // is pointing to the same memory as it was when we computed the alias. (anujg 8/13/99)
  856. if( ( 0UL != lpGblMore->fpAliasedVidMem ) &&
  857. ( lpGblMore->fpAliasOfVidMem == (FLATPTR) *pbits ) )
  858. {
  859. DPF( 4, "Lock vidmem pointer matches stored vidmem pointer - using cached alias" );
  860. paliasbits = lpGblMore->fpAliasedVidMem;
  861. }
  862. else
  863. {
  864. DPF( 4, "Lock vidmem pointer does not match vidmem pointer - recomputing" );
  865. paliasbits = GetAliasedVidMem( pdrv_lcl, this_lcl, (FLATPTR) *pbits );
  866. // Store this value for future use...
  867. if (this->fpVidMem == (FLATPTR)*pbits)
  868. {
  869. lpGblMore->fpAliasedVidMem = paliasbits;
  870. lpGblMore->fpAliasOfVidMem = this->fpVidMem;
  871. }
  872. }
  873. if( 0UL != paliasbits )
  874. {
  875. DPF( 5, "Got aliased pointer = 0x%08x", paliasbits );
  876. *pbits = (LPVOID) paliasbits;
  877. if( NULL != parl )
  878. parl->lpSurfaceData = *pbits;
  879. holdwin16lock = FALSE;
  880. pheapaliasinfo = pdrv->phaiHeapAliases;
  881. }
  882. }
  883. /*
  884. * If we have got this far for an execute buffer, it means that we have a
  885. * pointer to system memory even though the DDSCAPS_SYSTEMMEMORY is not
  886. * set. Thus it is ok to not hold the win16 lock, etc.
  887. * Basically what this amounts to is that we never take the win16 lock
  888. * for execute buffers. We first try and see if we can find an alias
  889. * to the pointer, and if we can't we assume it is in system memory and
  890. * not take the win16 lock in any case. (anujg 4/7/98)
  891. */
  892. if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
  893. {
  894. holdwin16lock = FALSE;
  895. }
  896. }
  897. }
  898. }
  899. }
  900. if( !holdwin16lock )
  901. {
  902. /*
  903. * We have an aliased lock so we don't need to hold onto the Win16
  904. * and busy bit. However, we do need to clear the VRAM bit in the
  905. * PDEVICE (if we have not done this already). We also need to
  906. * patch the DIB engine to correct the some of the problems we
  907. * have in turning the VRAM bit off. Once that is done we can
  908. * release the Win16 lock and BUSY bit.
  909. *
  910. * NOTE: We only need do this if there are no outstanding aliased
  911. * locks off this device
  912. *
  913. * NOTE #2: We also do not need to do this for aliased locks to
  914. * execute buffers as this is just trying to prevent DIB Engine
  915. * from using HW accelleration when there is an outstanding aliased lock
  916. * This is not necessary for the new HW which will be implementing EB
  917. * in video memory
  918. */
  919. if( 0UL == pdrv->dwAliasedLockCnt && !(this_lcl_caps & DDSCAPS_EXECUTEBUFFER))
  920. {
  921. BOOL vrambitset;
  922. pdflags = pdrv->lpwPDeviceFlags;
  923. /*
  924. * Clear the PDEVICE's VRAM bit and return its previous status
  925. * in vrambit
  926. */
  927. vrambitset = 0;
  928. _asm
  929. {
  930. mov eax, pdflags
  931. btr word ptr [eax], VRAM_BIT
  932. adc vrambitset,0
  933. }
  934. /*
  935. * We use a global device object flag to remember the original
  936. * state of the VRAM flag.
  937. */
  938. if( vrambitset )
  939. {
  940. /*
  941. * The VRAM bit in the PDEVICE was set. Need to record the fact
  942. * that it was cleared by a lock (so we can put the correct
  943. * state back).
  944. */
  945. DPF( 4, "VRAM bit was cleared for lock of surface 0x%08x", this_lcl );
  946. pdrv->dwFlags |= DDRAWI_PDEVICEVRAMBITCLEARED;
  947. }
  948. #ifdef DEBUG
  949. else
  950. {
  951. /*
  952. * NOTE: This can happen if we are running emulated.
  953. */
  954. DPF( 4, "VRAM bit was already clear on lock of surface 0x%08x", this_lcl );
  955. DDASSERT( !( pdrv->dwFlags & DDRAWI_PDEVICEVRAMBITCLEARED ) );
  956. }
  957. #endif
  958. }
  959. /*
  960. * Bump the count on the number of outstanding aliased locks.
  961. */
  962. pdrv->dwAliasedLockCnt++;
  963. if(!(this_lcl_caps & DDSCAPS_EXECUTEBUFFER))
  964. {
  965. // This is used to check if the graphics adapter is busy for Blts, Flips, etc
  966. // instead of dwAliasedLockCnt. This enables Blts & Flips when we have an
  967. // outstanding aliased lock to an exceute buffer since this will be common
  968. // in D3D. We increment this is all other cases to preserve original behavior.
  969. if( ( pdrv->lpDDKernelCaps == NULL ) ||
  970. !( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
  971. {
  972. pdrv->dwBusyDueToAliasedLock++;
  973. }
  974. }
  975. /*
  976. * If we are a real video memory surface then we need to hold a
  977. * reference to the heap aliases so they don't go away before we
  978. * unlock.
  979. */
  980. if( NULL != pheapaliasinfo )
  981. {
  982. DDASSERT( this_lcl_caps & DDSCAPS_VIDEOMEMORY );
  983. DDASSERT( pheapaliasinfo->dwFlags & HEAPALIASINFO_MAPPEDREAL );
  984. pheapaliasinfo->dwRefCnt++;
  985. }
  986. /*
  987. * Remember that this lock is using an alias and not holding the Win16 lock.
  988. */
  989. if( NULL != parl )
  990. {
  991. parl->lpHeapAliasInfo = pheapaliasinfo;
  992. parl->dwFlags |= ACCESSRECT_NOTHOLDINGWIN16LOCK;
  993. }
  994. else
  995. {
  996. this_lcl->lpSurfMore->lpHeapAliasInfo = pheapaliasinfo;
  997. this->dwGlobalFlags |= DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK;
  998. }
  999. /*
  1000. * All has gone well so there is no need to hold the Win16 lock and busy
  1001. * bit. Release them now.
  1002. */
  1003. doneBusyWin16Lock( pdrv );
  1004. /*
  1005. * We do not hold the DirectDraw critical section across the lock
  1006. * either.
  1007. */
  1008. LEAVE_DDRAW();
  1009. DPF( 5, "Win16 lock not held for lock of surface 0x%08x", this_lcl );
  1010. }
  1011. else
  1012. #endif /* USE_ALIAS */
  1013. {
  1014. /*
  1015. * We don't LEAVE_DDRAW() to avoid race conditions (someone
  1016. * could ENTER_DDRAW() and then wait on the Win16 lock but we
  1017. * can't release it because we can't get in the critical
  1018. * section).
  1019. * Even though we don't take the Win16 lock under NT, we
  1020. * continue to hold the DirectDraw critical section as
  1021. * long as a vram surface is locked.
  1022. */
  1023. pdrv->dwWin16LockCnt++;
  1024. DPF( 5, "Win16 lock was held for lock of surface 0x%08x", this_lcl );
  1025. }
  1026. }
  1027. else
  1028. {
  1029. LEAVE_DDRAW();
  1030. }
  1031. return DD_OK;
  1032. } /* InternalLock */
  1033. /*
  1034. * InternalUnlock
  1035. */
  1036. HRESULT InternalUnlock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID lpSurfaceData,
  1037. LPRECT lpDestRect, DWORD dwFlags )
  1038. {
  1039. LPDDRAWI_DDRAWSURFACE_GBL this;
  1040. DWORD rc;
  1041. DDHAL_UNLOCKDATA uld;
  1042. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  1043. LPDDRAWI_DIRECTDRAW_GBL pdrv;
  1044. LPDDHALSURFCB_UNLOCK ulhalfn;
  1045. LPDDHALSURFCB_UNLOCK ulfn;
  1046. BOOL emulation;
  1047. LPACCESSRECTLIST parl;
  1048. DWORD caps;
  1049. BOOL holdingwin16;
  1050. #ifdef USE_ALIAS
  1051. LPHEAPALIASINFO pheapaliasinfo;
  1052. BOOL lockbroken = FALSE;
  1053. #endif /* USE_ALIAS */
  1054. DDASSERT(lpSurfaceData == NULL || lpDestRect == NULL);
  1055. this = this_lcl->lpGbl;
  1056. pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
  1057. pdrv = pdrv_lcl->lpGbl;
  1058. caps = this_lcl->ddsCaps.dwCaps;
  1059. if( this->dwUsageCount == 0 )
  1060. {
  1061. DPF_ERR( "ERROR: Surface not locked." );
  1062. return DDERR_NOTLOCKED;
  1063. }
  1064. ENTER_DDRAW();
  1065. /* under NT we cannot compare the locked ptr with fpPrimary since
  1066. * a user-mode address may not necesarily match a kernel-mode
  1067. * address. Now we allocate an ACCESSRECTLIST structure on every
  1068. * lock, and store the user's vidmem ptr in that. The user's
  1069. * vidmem ptr cannot change between a lock and an unlock because
  1070. * the surface will be locked during that time (!) (even tho the
  1071. * physical ram that's mapped at that address might change... that
  1072. * win16lock avoidance thing). This is a very very small
  1073. * performance hit over doing it the old way. ah well. jeffno
  1074. * 960122 */
  1075. if( NULL != this->lpRectList )
  1076. {
  1077. DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
  1078. !(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
  1079. /*
  1080. * One or more locks are active on this surface.
  1081. */
  1082. if( NULL != lpDestRect || NULL != lpSurfaceData )
  1083. {
  1084. LPACCESSRECTLIST last;
  1085. BOOL found;
  1086. found = FALSE;
  1087. /*
  1088. * The locked region of the surface is specified by either a
  1089. * dest rect or a surface pointer (but never both). Find the
  1090. * specified region in our list of locked regions on this surface.
  1091. */
  1092. last = NULL;
  1093. parl = this->lpRectList;
  1094. if( NULL != lpDestRect )
  1095. {
  1096. /*
  1097. * Locked region of surface is specified by dest rect.
  1098. */
  1099. while( parl != NULL )
  1100. {
  1101. if( !memcmp(&parl->rDest, lpDestRect, sizeof(RECT)) )
  1102. {
  1103. found = TRUE;
  1104. break;
  1105. }
  1106. last = parl;
  1107. parl = parl->lpLink;
  1108. }
  1109. }
  1110. else
  1111. {
  1112. /*
  1113. * Locked region of surface is specified by surface ptr.
  1114. */
  1115. while( parl != NULL )
  1116. {
  1117. if( parl->lpSurfaceData == lpSurfaceData )
  1118. {
  1119. found = TRUE;
  1120. break;
  1121. }
  1122. last = parl;
  1123. parl = parl->lpLink;
  1124. }
  1125. }
  1126. /*
  1127. * did we find a match?
  1128. */
  1129. if( !found )
  1130. {
  1131. DPF_ERR( "Specified rectangle is not a locked area" );
  1132. LEAVE_DDRAW();
  1133. return DDERR_NOTLOCKED;
  1134. }
  1135. /*
  1136. * make sure unlocking process is the one who locked it
  1137. */
  1138. if( pdrv_lcl != parl->lpOwner )
  1139. {
  1140. DPF_ERR( "Current process did not lock this rectangle" );
  1141. LEAVE_DDRAW();
  1142. return DDERR_NOTLOCKED;
  1143. }
  1144. /*
  1145. * delete this rect
  1146. */
  1147. if( last == NULL )
  1148. {
  1149. this->lpRectList = parl->lpLink;
  1150. }
  1151. else
  1152. {
  1153. last->lpLink = parl->lpLink;
  1154. }
  1155. }
  1156. else
  1157. {
  1158. // Both lpDestRect and lpSurfaceData are null, so there better be
  1159. // only one lock on the surface - the whole thing. Make sure that
  1160. // if no rectangle was specified that there's only one entry in the
  1161. // access list - the one that was made during lock.
  1162. parl = this->lpRectList;
  1163. if( parl->lpLink == NULL )
  1164. {
  1165. DPF(5,"--Unlock: parl->rDest really set to (L=%d,T=%d,R=%d,B=%d)",
  1166. parl->rDest.left, parl->rDest.top, parl->rDest.right, parl->rDest.bottom);
  1167. /*
  1168. * make sure unlocking process is the one who locked it
  1169. */
  1170. if( pdrv_lcl != parl->lpOwner )
  1171. {
  1172. DPF_ERR( "Current process did not lock this rectangle" );
  1173. LEAVE_DDRAW();
  1174. return DDERR_NOTLOCKED; //what's a better error than this?
  1175. }
  1176. this->lpRectList = NULL;
  1177. }
  1178. else
  1179. {
  1180. DPF_ERR( "Multiple locks on surface -- you must specify a rectangle" );
  1181. LEAVE_DDRAW();
  1182. return DDERR_INVALIDRECT;
  1183. }
  1184. }
  1185. DDASSERT( NULL != parl );
  1186. if( parl->dwFlags & ACCESSRECT_NOTHOLDINGWIN16LOCK )
  1187. {
  1188. holdingwin16 = FALSE;
  1189. #ifdef USE_ALIAS
  1190. /*
  1191. * This flag should only be set for VRAM style locks.
  1192. */
  1193. DDASSERT( parl->dwFlags & ACCESSRECT_VRAMSTYLE );
  1194. pheapaliasinfo = parl->lpHeapAliasInfo;
  1195. #endif /* USE_ALIAS */
  1196. }
  1197. else
  1198. {
  1199. holdingwin16 = TRUE;
  1200. }
  1201. #ifdef USE_ALIAS
  1202. if( parl->dwFlags & ACCESSRECT_BROKEN )
  1203. lockbroken = TRUE;
  1204. #endif /* USE_ALIAS */
  1205. MemFree( parl );
  1206. }
  1207. else
  1208. {
  1209. /*
  1210. * Lock of the entire surface (no access rect). Determine whether
  1211. * this lock held the Win16 lock by using global surface object
  1212. * flags (as we have no access rect).
  1213. */
  1214. if( this->dwGlobalFlags & DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK )
  1215. {
  1216. holdingwin16 = FALSE;
  1217. #ifdef USE_ALIAS
  1218. /*
  1219. * This flag should only get set for VRAM style locks.
  1220. */
  1221. DDASSERT( this->dwGlobalFlags & DDRAWISURFGBL_LOCKVRAMSTYLE );
  1222. pheapaliasinfo = this_lcl->lpSurfMore->lpHeapAliasInfo;
  1223. this_lcl->lpSurfMore->lpHeapAliasInfo = NULL;
  1224. #endif /* USE_ALIAS */
  1225. }
  1226. else
  1227. {
  1228. holdingwin16 = TRUE;
  1229. }
  1230. #ifdef USE_ALIAS
  1231. if( this->dwGlobalFlags & DDRAWISURFGBL_LOCKBROKEN )
  1232. lockbroken = TRUE;
  1233. #endif /* USE_ALIAS */
  1234. this->dwGlobalFlags &= ~( DDRAWISURFGBL_LOCKVRAMSTYLE |
  1235. DDRAWISURFGBL_LOCKBROKEN |
  1236. DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK );
  1237. }
  1238. #ifdef WINNT
  1239. if (this->dwGlobalFlags & DDRAWISURFGBL_NOTIFYWHENUNLOCKED)
  1240. {
  1241. if (--dwNumLockedWhenModeSwitched == 0)
  1242. {
  1243. NotifyDriverOfFreeAliasedLocks();
  1244. }
  1245. this->dwGlobalFlags &= ~DDRAWISURFGBL_NOTIFYWHENUNLOCKED;
  1246. }
  1247. #endif
  1248. /*
  1249. * remove one of the users...
  1250. */
  1251. this->dwUsageCount--;
  1252. CHANGE_GLOBAL_CNT( pdrv, this, -1 );
  1253. #ifdef USE_ALIAS
  1254. /*
  1255. * The semantics I have choosen for surfaces which are locked when they
  1256. * get themselves invalidates is to make the application call unlock the
  1257. * appropriate number of times (this for our housekeeping and also for
  1258. * back compatability with existing applications which don't expect to
  1259. * lose locked surfaces and so we be set up to call lock regardless.
  1260. * However, in the case of surfaces that are released when locked we
  1261. * break the locks but don't call the unlock method in the driver we
  1262. * mirror that here. If a lock has been broken we don't call the HAL.
  1263. */
  1264. if( !lockbroken )
  1265. {
  1266. #endif /* USE_ALIAS */
  1267. /*
  1268. * Is this an emulation surface or driver surface?
  1269. *
  1270. * NOTE: Different HAL entry points for execute
  1271. * buffers.
  1272. */
  1273. if( (caps & DDSCAPS_SYSTEMMEMORY) ||
  1274. (this_lcl->dwFlags & DDRAWISURF_HELCB) )
  1275. {
  1276. if( caps & DDSCAPS_EXECUTEBUFFER )
  1277. ulfn = pdrv_lcl->lpDDCB->HELDDExeBuf.UnlockExecuteBuffer;
  1278. else
  1279. ulfn = pdrv_lcl->lpDDCB->HELDDSurface.Unlock;
  1280. ulhalfn = ulfn;
  1281. emulation = TRUE;
  1282. }
  1283. else
  1284. {
  1285. if( caps & DDSCAPS_EXECUTEBUFFER )
  1286. {
  1287. ulfn = pdrv_lcl->lpDDCB->HALDDExeBuf.UnlockExecuteBuffer;
  1288. ulhalfn = pdrv_lcl->lpDDCB->cbDDExeBufCallbacks.UnlockExecuteBuffer;
  1289. }
  1290. else
  1291. {
  1292. ulfn = pdrv_lcl->lpDDCB->HALDDSurface.Unlock;
  1293. ulhalfn = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Unlock;
  1294. }
  1295. emulation = FALSE;
  1296. }
  1297. /*
  1298. * Let the driver know about the unlock.
  1299. */
  1300. uld.ddRVal = DD_OK;
  1301. if( ulhalfn != NULL )
  1302. {
  1303. uld.Unlock = ulhalfn;
  1304. uld.lpDD = pdrv;
  1305. uld.lpDDSurface = this_lcl;
  1306. if( caps & DDSCAPS_EXECUTEBUFFER )
  1307. {
  1308. DOHALCALL( UnlockExecuteBuffer, ulfn, uld, rc, emulation );
  1309. }
  1310. else
  1311. {
  1312. DOHALCALL( Unlock, ulfn, uld, rc, emulation );
  1313. }
  1314. if( rc != DDHAL_DRIVER_HANDLED )
  1315. {
  1316. uld.ddRVal = DD_OK;
  1317. }
  1318. }
  1319. #ifdef USE_ALIAS
  1320. }
  1321. else
  1322. {
  1323. DPF( 4, "Lock broken - not calling HAL on Unlock" );
  1324. uld.ddRVal = DD_OK;
  1325. }
  1326. #endif /* USE_ALIAS */
  1327. /* Release the win16 lock but only if the corresponding lock took
  1328. * the win16 lock which in the case of the API level lock and
  1329. * unlock calls is if the user requests it and the surface was not
  1330. * explicitly allocated in system memory.
  1331. *
  1332. * IMPORTANT NOTE: Again we no longer only do this for the first lock
  1333. * on a surface. This matches the code path for lock.
  1334. */
  1335. if( ( ((dwFlags & DDLOCK_TAKE_WIN16) && !(this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED)) ||
  1336. ((dwFlags & DDLOCK_TAKE_WIN16_VRAM) && (caps & DDSCAPS_VIDEOMEMORY)) )
  1337. && (pdrv->dwFlags & DDRAWI_DISPLAYDRV) )
  1338. {
  1339. DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
  1340. !(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
  1341. if( !holdingwin16 )
  1342. {
  1343. #ifdef USE_ALIAS
  1344. /*
  1345. * Cleanup the PDEVICE's VRAM bit (if this is the last outstanding
  1346. * VRAM lock.
  1347. */
  1348. undoAliasedLock( pdrv );
  1349. if(!(caps & DDSCAPS_EXECUTEBUFFER))
  1350. {
  1351. // This is used to check if the graphics adapter is busy for Blts, Flips, etc
  1352. // instead of dwAliasedLockCnt. Make sure we decrement it for everything but
  1353. // execute buffers.
  1354. if( ( pdrv->lpDDKernelCaps == NULL ) ||
  1355. !( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
  1356. {
  1357. pdrv->dwBusyDueToAliasedLock--;
  1358. }
  1359. }
  1360. /*
  1361. * We don't need the aliases anymore.
  1362. *
  1363. * NOTE: We don't actually have to have an alias. If this is
  1364. * a VRAM style lock of an implicit system memory surface then
  1365. * no alias is actually used.
  1366. */
  1367. if( NULL != pheapaliasinfo )
  1368. {
  1369. DDASSERT( 0UL != pdrv_lcl->hDDVxd );
  1370. ReleaseHeapAliases( (HANDLE) pdrv_lcl->hDDVxd, pheapaliasinfo );
  1371. }
  1372. #endif /* USE_ALIAS */
  1373. }
  1374. else
  1375. {
  1376. tryDoneLock( pdrv_lcl, 0 );
  1377. }
  1378. /*
  1379. * If it was a vram lock then we did not release the DirectDraw critical
  1380. * section on the lock. We need to release it now.
  1381. */
  1382. }
  1383. // Unexclude the cursor if it was excluded in Lock.
  1384. DONE_LOCK_EXCLUDE();
  1385. LEAVE_DDRAW();
  1386. return uld.ddRVal;
  1387. } /* InternalUnlock */
  1388. #undef DPF_MODNAME
  1389. #define DPF_MODNAME "Lock"
  1390. /*
  1391. * DD_Surface_Lock
  1392. *
  1393. * Allows access to a surface.
  1394. *
  1395. * A pointer to the video memory is returned. The primary surface
  1396. * can change from call to call, if page flipping is turned on.
  1397. */
  1398. //#define ALLOW_COPY_ON_LOCK
  1399. #ifdef ALLOW_COPY_ON_LOCK
  1400. HDC hdcPrimaryCopy=0;
  1401. HBITMAP hbmPrimaryCopy=0;
  1402. #endif
  1403. HRESULT DDAPI DD_Surface_Lock(
  1404. LPDIRECTDRAWSURFACE lpDDSurface,
  1405. LPRECT lpDestRect,
  1406. LPDDSURFACEDESC lpDDSurfaceDesc,
  1407. DWORD dwFlags,
  1408. HANDLE hEvent )
  1409. {
  1410. LPDDRAWI_DDRAWSURFACE_INT this_int;
  1411. LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
  1412. LPDDRAWI_DDRAWSURFACE_GBL this;
  1413. DWORD this_lcl_caps;
  1414. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  1415. LPDDRAWI_DIRECTDRAW_GBL pdrv;
  1416. HRESULT ddrval;
  1417. LPVOID pbits;
  1418. BOOL fastlock;
  1419. ENTER_DDRAW();
  1420. DPF(2,A,"ENTERAPI: DD_Surface_Lock %p", ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSurface)->lpLcl);
  1421. if (lpDestRect != NULL)
  1422. DPF(2,A,"Lock rectangle (%d, %d, %d, %d)", lpDestRect->left, lpDestRect->top, lpDestRect->right, lpDestRect->bottom);
  1423. /* DPF_ENTERAPI(lpDDSurface); */
  1424. /*
  1425. * Problem: Under NT, there is no cross-process pointer to any given video-memory surface.
  1426. * So how do you tell if an lpVidMem you passed back to the user is the same as the fpPrimaryOrig that
  1427. * was previously stored in the ddraw gbl struct? You can't. Previously, we did a special case lock
  1428. * when the user requested the whole surface (lpDestRect==NULL). Now we allocate a ACCESSRECTLIST
  1429. * structure on every lock, and if lpDestRect==NULL, we put the top-left vidmemptr into that structure.
  1430. * Notice we can guarantee that this ptr will be valid at unlock time because the surface remains
  1431. * locked for all that time (obviously!).
  1432. * This is a minor minor minor perf hit, but what the hey.
  1433. * jeffno 960122
  1434. */
  1435. TRY
  1436. {
  1437. /*
  1438. * validate parms
  1439. */
  1440. this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSurface;
  1441. if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
  1442. {
  1443. LEAVE_DDRAW();
  1444. return DDERR_INVALIDOBJECT;
  1445. }
  1446. this_lcl = this_int->lpLcl;
  1447. this = this_lcl->lpGbl;
  1448. this_lcl_caps = this_lcl->ddsCaps.dwCaps;
  1449. pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
  1450. pdrv = pdrv_lcl->lpGbl;
  1451. if( SURFACE_LOST( this_lcl ) )
  1452. {
  1453. LEAVE_DDRAW();
  1454. return DDERR_SURFACELOST;
  1455. }
  1456. fastlock = (this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW7) &&
  1457. (NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus ||
  1458. !(this->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED)) &&
  1459. !(this_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT) &&
  1460. (this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED) &&
  1461. (this_lcl_caps & DDSCAPS_TEXTURE);
  1462. #ifndef DEBUG
  1463. if(!fastlock)
  1464. #endif
  1465. {
  1466. if (this_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
  1467. {
  1468. DPF_ERR( "It is an optimized surface" );
  1469. LEAVE_DDRAW();
  1470. return DDERR_ISOPTIMIZEDSURFACE;
  1471. }
  1472. if( dwFlags & ~DDLOCK_VALID )
  1473. {
  1474. DPF_ERR( "Invalid flags" );
  1475. LEAVE_DDRAW();
  1476. return DDERR_INVALIDPARAMS;
  1477. }
  1478. if (!LOWERTHANSURFACE7(this_int))
  1479. {
  1480. if (dwFlags & DDLOCK_DONOTWAIT)
  1481. {
  1482. dwFlags &= ~DDLOCK_WAIT;
  1483. }
  1484. else
  1485. {
  1486. dwFlags |= DDLOCK_WAIT;
  1487. }
  1488. }
  1489. if( !VALID_DDSURFACEDESC_PTR( lpDDSurfaceDesc ) &&
  1490. !VALID_DDSURFACEDESC2_PTR( lpDDSurfaceDesc ) )
  1491. {
  1492. DPF_ERR( "Invalid surface description ptr" );
  1493. LEAVE_DDRAW();
  1494. return DDERR_INVALIDPARAMS;
  1495. }
  1496. lpDDSurfaceDesc->lpSurface = NULL;
  1497. /*
  1498. * Make sure the process locking this surface is the one
  1499. * that created it.
  1500. */
  1501. if( this_lcl->dwProcessId != GetCurrentProcessId() )
  1502. {
  1503. DPF_ERR( "Current process did not create this surface" );
  1504. LEAVE_DDRAW();
  1505. return DDERR_SURFACEBUSY;
  1506. }
  1507. /* Check out the rectangle, if any.
  1508. *
  1509. * NOTE: We don't allow the specification of a rectangle with an
  1510. * execute buffer.
  1511. */
  1512. if( lpDestRect != NULL )
  1513. {
  1514. if( !VALID_RECT_PTR( lpDestRect ) || ( this_lcl_caps & DDSCAPS_EXECUTEBUFFER ) )
  1515. {
  1516. DPF_ERR( "Invalid destination rectangle pointer" );
  1517. LEAVE_DDRAW();
  1518. return DDERR_INVALIDPARAMS;
  1519. } // valid pointer
  1520. /*
  1521. * make sure rectangle is OK
  1522. */
  1523. if( (lpDestRect->left < 0) ||
  1524. (lpDestRect->top < 0) ||
  1525. (lpDestRect->left > lpDestRect->right) ||
  1526. (lpDestRect->top > lpDestRect->bottom) ||
  1527. (lpDestRect->bottom > (int) (DWORD) this->wHeight) ||
  1528. (lpDestRect->right > (int) (DWORD) this->wWidth) )
  1529. {
  1530. DPF_ERR( "Invalid rectangle given" );
  1531. LEAVE_DDRAW();
  1532. return DDERR_INVALIDPARAMS;
  1533. } // checking rectangle
  1534. }
  1535. }
  1536. }
  1537. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1538. {
  1539. DPF_ERR( "Exception encountered validating parameters" );
  1540. LEAVE_DDRAW();
  1541. return DDERR_INVALIDPARAMS;
  1542. }
  1543. if(fastlock)
  1544. {
  1545. DPF(4, "Performing fast lock");
  1546. lpDDSurfaceDesc->lpSurface = NULL;
  1547. #ifdef DEBUG
  1548. if(this->fpVidMem != (FLATPTR)NULL)
  1549. {
  1550. if(this->fpVidMem != (FLATPTR)0xFFBADBAD)
  1551. #endif
  1552. {
  1553. if(this->dwUsageCount == 0)
  1554. {
  1555. FlushD3DStates(this_lcl);
  1556. #if COLLECTSTATS
  1557. if(this_lcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
  1558. ++this_lcl->lpSurfMore->lpDD_lcl->dwNumTexLocks;
  1559. #endif
  1560. if( lpDestRect != NULL )
  1561. {
  1562. DWORD byte_offset;
  1563. /*
  1564. * Add a rect to the region list if this is a managed surface and not a read only lock
  1565. */
  1566. if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
  1567. {
  1568. LPREGIONLIST lpRegionList = this_lcl->lpSurfMore->lpRegionList;
  1569. if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
  1570. {
  1571. lpRegionList->rect[(lpRegionList->rdh.nCount)++] = *((LPRECTL)lpDestRect);
  1572. lpRegionList->rdh.nRgnSize += sizeof(RECT);
  1573. if(lpDestRect->left < lpRegionList->rdh.rcBound.left)
  1574. lpRegionList->rdh.rcBound.left = lpDestRect->left;
  1575. if(lpDestRect->right > lpRegionList->rdh.rcBound.right)
  1576. lpRegionList->rdh.rcBound.right = lpDestRect->right;
  1577. if(lpDestRect->top < lpRegionList->rdh.rcBound.top)
  1578. lpRegionList->rdh.rcBound.top = lpDestRect->top;
  1579. if(lpDestRect->bottom > lpRegionList->rdh.rcBound.bottom)
  1580. lpRegionList->rdh.rcBound.bottom = lpDestRect->bottom;
  1581. }
  1582. MarkDirty(this_lcl);
  1583. }
  1584. // Make the surface pointer point to the first byte of the requested rectangle.
  1585. switch((this_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) ? this->ddpfSurface.dwRGBBitCount : pdrv->vmiData.ddpfDisplay.dwRGBBitCount)
  1586. {
  1587. case 1: byte_offset = ((DWORD)lpDestRect->left)>>3; break;
  1588. case 2: byte_offset = ((DWORD)lpDestRect->left)>>2; break;
  1589. case 4: byte_offset = ((DWORD)lpDestRect->left)>>1; break;
  1590. case 8: byte_offset = (DWORD)lpDestRect->left; break;
  1591. case 16: byte_offset = (DWORD)lpDestRect->left*2; break;
  1592. case 24: byte_offset = (DWORD)lpDestRect->left*3; break;
  1593. case 32: byte_offset = (DWORD)lpDestRect->left*4; break;
  1594. }
  1595. pbits = (LPVOID) ((ULONG_PTR)this->fpVidMem + (DWORD)lpDestRect->top * this->lPitch + byte_offset);
  1596. }
  1597. else
  1598. {
  1599. /*
  1600. * We are locking the whole surface, so by setting nCount to the
  1601. * max number of dirty rects allowed, we will force the cache
  1602. * manager to update the entire surface
  1603. */
  1604. if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
  1605. {
  1606. this_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
  1607. MarkDirty(this_lcl);
  1608. }
  1609. pbits = (LPVOID) this->fpVidMem;
  1610. }
  1611. // Increment the usage count of this surface.
  1612. this->dwUsageCount++;
  1613. // Reset hardware op status
  1614. this->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED;
  1615. // Free cached RLE data
  1616. if( GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved )
  1617. {
  1618. MemFree( (void *)(GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved) );
  1619. GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved = 0;
  1620. }
  1621. this->dwGlobalFlags |= DDRAWISURFGBL_FASTLOCKHELD;
  1622. ddrval = DD_OK;
  1623. }
  1624. else
  1625. {
  1626. DPF_ERR("Surface already locked");
  1627. ddrval = DDERR_SURFACEBUSY;
  1628. }
  1629. }
  1630. #ifdef DEBUG
  1631. else
  1632. {
  1633. this->dwGlobalFlags |= DDRAWISURFGBL_FASTLOCKHELD;
  1634. ddrval = DD_OK;
  1635. }
  1636. }
  1637. else
  1638. {
  1639. ddrval = DDERR_GENERIC;
  1640. }
  1641. #endif
  1642. }
  1643. else
  1644. {
  1645. // Params are okay, so call InternalLock() to do the work.
  1646. ddrval = InternalLock(this_lcl, &pbits, lpDestRect, dwFlags | DDLOCK_TAKE_WIN16 | DDLOCK_FAILEMULATEDNTPRIMARY);
  1647. }
  1648. if(ddrval != DD_OK)
  1649. {
  1650. if( (ddrval != DDERR_WASSTILLDRAWING) && (ddrval != DDERR_SURFACELOST) )//both useless as spew
  1651. {
  1652. DPF_ERR("InternalLock failed.");
  1653. }
  1654. LEAVE_DDRAW();
  1655. return ddrval;
  1656. }
  1657. if (dwFlags & DDLOCK_READONLY)
  1658. this->dwGlobalFlags |= DDRAWISURFGBL_READONLYLOCKHELD;
  1659. else
  1660. this->dwGlobalFlags &= ~DDRAWISURFGBL_READONLYLOCKHELD;
  1661. FillEitherDDSurfaceDesc( this_lcl, (LPDDSURFACEDESC2) lpDDSurfaceDesc );
  1662. lpDDSurfaceDesc->lpSurface = pbits;
  1663. DPF_STRUCT(3,A,DDSURFACEDESC,lpDDSurfaceDesc);
  1664. LEAVE_DDRAW();
  1665. return DD_OK;
  1666. } /* DD_Surface_Lock */
  1667. #undef DPF_MODNAME
  1668. #define DPF_MODNAME "Unlock"
  1669. /*
  1670. * Perform the parameter checking and surface unlocking for the
  1671. * IDirectDrawSurface::Unlock API call. This function is called
  1672. * from both the DD_Surface_Unlock and DD_Surface_Unlock4 entry
  1673. * points. Argument lpSurfaceData is always NULL when the call
  1674. * is from DD_SurfaceUnlock4, and argument lpDestRect is always
  1675. * NULL when the call is from DD_Surface_Unlock.
  1676. */
  1677. HRESULT unlockMain(
  1678. LPDIRECTDRAWSURFACE lpDDSurface,
  1679. LPVOID lpSurfaceData,
  1680. LPRECT lpDestRect )
  1681. {
  1682. LPDDRAWI_DDRAWSURFACE_INT this_int;
  1683. LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
  1684. LPDDRAWI_DDRAWSURFACE_GBL this;
  1685. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  1686. LPDDRAWI_DIRECTDRAW_GBL pdrv;
  1687. LPACCESSRECTLIST parl;
  1688. HRESULT err;
  1689. /*
  1690. * validate parameters
  1691. */
  1692. TRY
  1693. {
  1694. this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSurface;
  1695. if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
  1696. {
  1697. return DDERR_INVALIDOBJECT;
  1698. }
  1699. this_lcl = this_int->lpLcl;
  1700. this = this_lcl->lpGbl;
  1701. pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
  1702. pdrv = pdrv_lcl->lpGbl;
  1703. #ifndef DEBUG
  1704. if(!(this->dwGlobalFlags & DDRAWISURFGBL_FASTLOCKHELD))
  1705. #endif
  1706. {
  1707. //
  1708. // For now, if the current surface is optimized, quit
  1709. //
  1710. if (this_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
  1711. {
  1712. DPF_ERR( "It is an optimized surface" );
  1713. return DDERR_ISOPTIMIZEDSURFACE;
  1714. }
  1715. if (lpDestRect != NULL)
  1716. {
  1717. /*
  1718. * Make sure the specified rectangle pointer is valid.
  1719. */
  1720. if (!VALID_RECT_PTR(lpDestRect))
  1721. {
  1722. DPF_ERR( "Invalid destination rectangle pointer" );
  1723. return DDERR_INVALIDPARAMS;
  1724. }
  1725. }
  1726. /*
  1727. * make sure process accessed this surface
  1728. */
  1729. if( this_lcl->dwProcessId != GetCurrentProcessId() )
  1730. {
  1731. DPF_ERR( "Current process did not lock this surface" );
  1732. return DDERR_NOTLOCKED;
  1733. }
  1734. /*
  1735. * was surface accessed?
  1736. */
  1737. if( this->dwUsageCount == 0 )
  1738. {
  1739. return DDERR_NOTLOCKED;
  1740. }
  1741. /*
  1742. * if the usage count is bigger than one, then you had better tell
  1743. * me what region of the screen you were using...
  1744. */
  1745. if( this->dwUsageCount > 1 && lpSurfaceData == NULL && lpDestRect == NULL)
  1746. {
  1747. return DDERR_INVALIDRECT;
  1748. }
  1749. /*
  1750. * We don't want apps to hold a DC when the surface is not locked,
  1751. * but failing right now could cause regression issues, so we will
  1752. * output a banner when we see this an fail on the new interfaces.
  1753. */
  1754. if( ( this_lcl->dwFlags & DDRAWISURF_HASDC ) &&
  1755. !( this_lcl->ddsCaps.dwCaps & DDSCAPS_OWNDC ) )
  1756. {
  1757. DPF_ERR( "***************************************************" );
  1758. DPF_ERR( "** Application called Unlock w/o releasing the DC!!" );
  1759. DPF_ERR( "***************************************************" );
  1760. if( ( this_int->lpVtbl != &ddSurfaceCallbacks ) &&
  1761. ( this_int->lpVtbl != &ddSurface2Callbacks ) )
  1762. {
  1763. return DDERR_GENERIC;
  1764. }
  1765. }
  1766. /*
  1767. * if no rect list, no one has locked
  1768. */
  1769. parl = this->lpRectList;
  1770. }
  1771. }
  1772. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1773. {
  1774. DPF_ERR( "Exception encountered validating parameters" );
  1775. return DDERR_INVALIDPARAMS;
  1776. }
  1777. if(this->dwGlobalFlags & DDRAWISURFGBL_FASTLOCKHELD)
  1778. {
  1779. DPF(4, "Performing fast unlock");
  1780. --this->dwUsageCount;
  1781. DDASSERT(this->dwUsageCount == 0);
  1782. err = DD_OK;
  1783. this->dwGlobalFlags &= ~DDRAWISURFGBL_FASTLOCKHELD;
  1784. }
  1785. else
  1786. {
  1787. err = InternalUnlock(this_lcl,lpSurfaceData,lpDestRect,DDLOCK_TAKE_WIN16);
  1788. }
  1789. //We only bump the surface stamp if the lock was NOT read only
  1790. if ( (this->dwGlobalFlags & DDRAWISURFGBL_READONLYLOCKHELD) == 0)
  1791. {
  1792. DPF(4,"Bumping surface stamp");
  1793. BUMP_SURFACE_STAMP(this);
  1794. }
  1795. this->dwGlobalFlags &= ~DDRAWISURFGBL_READONLYLOCKHELD;
  1796. #ifdef WINNT
  1797. if( SURFACE_LOST( this_lcl ) )
  1798. {
  1799. err = DDERR_SURFACELOST;
  1800. }
  1801. #endif
  1802. return err;
  1803. } /* unlockMain */
  1804. /*
  1805. * DD_Surface_Unlock
  1806. *
  1807. * Done accessing a surface. This is the version used for interfaces
  1808. * IDirectDrawSurface, IDirectDrawSurface2, and IDirectDrawSurface3.
  1809. */
  1810. HRESULT DDAPI DD_Surface_Unlock(
  1811. LPDIRECTDRAWSURFACE lpDDSurface,
  1812. LPVOID lpSurfaceData )
  1813. {
  1814. LPDDRAWI_DDRAWSURFACE_INT this_int;
  1815. LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
  1816. LPDDRAWI_DDRAWSURFACE_GBL this;
  1817. HRESULT ddrval;
  1818. ENTER_DDRAW();
  1819. DPF(2,A,"ENTERAPI: DD_Surface_Unlock %p", lpDDSurface);
  1820. ddrval = unlockMain(lpDDSurface, lpSurfaceData, NULL);
  1821. LEAVE_DDRAW();
  1822. return (ddrval);
  1823. } /* DD_Surface_Unlock */
  1824. /*
  1825. * DD_Surface_Unlock4
  1826. *
  1827. * Done accessing a surface. This is the version used for interfaces
  1828. * IDirectDrawSurface4 and higher.
  1829. */
  1830. HRESULT DDAPI DD_Surface_Unlock4(
  1831. LPDIRECTDRAWSURFACE lpDDSurface,
  1832. LPRECT lpDestRect )
  1833. {
  1834. HRESULT ddrval;
  1835. RECT rDest;
  1836. ENTER_DDRAW();
  1837. DPF(2,A,"ENTERAPI: DD_Surface_Unlock4");
  1838. ddrval = unlockMain(lpDDSurface, NULL, lpDestRect);
  1839. LEAVE_DDRAW();
  1840. return (ddrval);
  1841. } /* DD_Surface_Unlock4 */
  1842. #ifdef USE_ALIAS
  1843. /*
  1844. * BreakSurfaceLocks
  1845. *
  1846. * Mark any locks held by a surface as broken. This is called when
  1847. * invalidating a surface (due to a mode switch). The semantics are
  1848. * that a surface destroy is an implict unlock on all locks on the
  1849. * surface. Thus, we don't call the HAL unlock, only the HAL destroy.
  1850. */
  1851. void BreakSurfaceLocks( LPDDRAWI_DDRAWSURFACE_GBL this )
  1852. {
  1853. LPACCESSRECTLIST lpRect;
  1854. DPF( 4, "Breaking locks on the surface 0x%08x", this );
  1855. if( 0UL != this->dwUsageCount )
  1856. {
  1857. if( NULL != this->lpRectList )
  1858. {
  1859. for( lpRect = this->lpRectList; NULL != lpRect; lpRect = lpRect->lpLink )
  1860. lpRect->dwFlags |= ACCESSRECT_BROKEN;
  1861. }
  1862. else
  1863. {
  1864. DDASSERT( 1UL == this->dwUsageCount );
  1865. this->dwGlobalFlags |= DDRAWISURFGBL_LOCKBROKEN;
  1866. }
  1867. }
  1868. } /* BreakSurfaceLocks */
  1869. #endif /* USE_ALIAS */
  1870. /*
  1871. * RemoveProcessLocks
  1872. *
  1873. * Remove all Lock calls made a by process on a surface.
  1874. * assumes driver lock is taken
  1875. */
  1876. void RemoveProcessLocks(
  1877. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl,
  1878. LPDDRAWI_DDRAWSURFACE_LCL this_lcl,
  1879. DWORD pid )
  1880. {
  1881. LPDDRAWI_DIRECTDRAW_GBL pdrv=pdrv_lcl->lpGbl;
  1882. LPDDRAWI_DDRAWSURFACE_GBL this=this_lcl->lpGbl;
  1883. DWORD refcnt;
  1884. LPACCESSRECTLIST parl;
  1885. LPACCESSRECTLIST last;
  1886. LPACCESSRECTLIST next;
  1887. /*
  1888. * remove all rectangles we have accessed
  1889. */
  1890. refcnt = (DWORD) this->dwUsageCount;
  1891. if( refcnt == 0 )
  1892. {
  1893. return;
  1894. }
  1895. parl = this->lpRectList;
  1896. last = NULL;
  1897. while( parl != NULL )
  1898. {
  1899. next = parl->lpLink;
  1900. if( parl->lpOwner == pdrv_lcl )
  1901. {
  1902. DPF( 5, "Cleaning up lock to rectangle (%ld,%ld),(%ld,%ld) by pid %08lx",
  1903. parl->rDest.left,parl->rDest.top,
  1904. parl->rDest.right,parl->rDest.bottom,
  1905. pid );
  1906. refcnt--;
  1907. this->dwUsageCount--;
  1908. CHANGE_GLOBAL_CNT( pdrv, this, -1 );
  1909. #ifdef USE_ALIAS
  1910. /*
  1911. * If this was a vram style lock and it didn't hold the Win16 lock
  1912. * then we need to decrement the number of aliased locks held.
  1913. */
  1914. if( ( parl->dwFlags & ACCESSRECT_VRAMSTYLE ) &&
  1915. ( parl->dwFlags & ACCESSRECT_NOTHOLDINGWIN16LOCK ) )
  1916. {
  1917. DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
  1918. undoAliasedLock( pdrv );
  1919. if(!(this_lcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
  1920. {
  1921. // This is used to check if the graphics adapter is busy for Blts, Flips, etc
  1922. // instead of dwAliasedLockCnt. Make sure we decrement it for everything but
  1923. // execute buffers.
  1924. if( ( pdrv->lpDDKernelCaps == NULL ) ||
  1925. !( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
  1926. {
  1927. pdrv->dwBusyDueToAliasedLock--;
  1928. }
  1929. }
  1930. /*
  1931. * If we are holding a referenced to an aliased heap release it
  1932. * now.
  1933. */
  1934. if( NULL != parl->lpHeapAliasInfo )
  1935. ReleaseHeapAliases( GETDDVXDHANDLE( pdrv_lcl ) , parl->lpHeapAliasInfo );
  1936. }
  1937. #endif /* USE_ALIAS */
  1938. if( last == NULL )
  1939. {
  1940. this->lpRectList = next;
  1941. }
  1942. else
  1943. {
  1944. last->lpLink = next;
  1945. }
  1946. MemFree( parl );
  1947. }
  1948. else
  1949. {
  1950. last = parl;
  1951. }
  1952. parl = next;
  1953. }
  1954. #ifdef USE_ALIAS
  1955. /*
  1956. * Was the entire surface locked with a video memory style
  1957. * lock (but without the Win16 lock held)? If so then we
  1958. * again need to decrement the aliased lock count.
  1959. */
  1960. if( ( this->dwGlobalFlags & DDRAWISURFGBL_LOCKVRAMSTYLE ) &&
  1961. ( this->dwGlobalFlags & DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK ) )
  1962. {
  1963. DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
  1964. undoAliasedLock( pdrv );
  1965. if(!(this_lcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
  1966. {
  1967. // This is used to check if the graphics adapter is busy for Blts, Flips, etc
  1968. // instead of dwAliasedLockCnt. Make sure we decrement it for everything but
  1969. // execute buffers.
  1970. if( ( pdrv->lpDDKernelCaps == NULL ) ||
  1971. !( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
  1972. {
  1973. pdrv->dwBusyDueToAliasedLock--;
  1974. }
  1975. }
  1976. /*
  1977. * If we are holding a referenced to an aliased heap release it
  1978. * now.
  1979. */
  1980. if( NULL != this_lcl->lpSurfMore->lpHeapAliasInfo )
  1981. {
  1982. ReleaseHeapAliases( GETDDVXDHANDLE( pdrv_lcl ), this_lcl->lpSurfMore->lpHeapAliasInfo );
  1983. this_lcl->lpSurfMore->lpHeapAliasInfo = NULL;
  1984. }
  1985. }
  1986. #endif /* USE_ALIAS */
  1987. /*
  1988. * remove the last of the refcnts we have
  1989. */
  1990. this->dwUsageCount -= (short) refcnt;
  1991. CHANGE_GLOBAL_CNT( pdrv, this, -1*refcnt );
  1992. /*
  1993. * clean up the win16 lock
  1994. *
  1995. * NOTE: This is not surface related this just breaks the Win16
  1996. * lock and device busy bits held by the device. You realy only
  1997. * want to do this once not once per surface.
  1998. */
  1999. /*
  2000. * blow away extra locks if the the process is still alive
  2001. */
  2002. if( pid == GetCurrentProcessId() )
  2003. {
  2004. DPF( 5, "Cleaning up %ld Win16 locks", pdrv->dwWin16LockCnt );
  2005. while( pdrv->dwWin16LockCnt > 0 )
  2006. {
  2007. tryDoneLock( pdrv_lcl, pid );
  2008. }
  2009. }
  2010. else
  2011. {
  2012. /*
  2013. * !!! NOTE: Does not reset the BUSY bit!
  2014. */
  2015. DPF( 4, "Process dead, resetting Win16 lock cnt" );
  2016. pdrv->dwWin16LockCnt = 0;
  2017. }
  2018. DPF( 5, "Cleaned up %ld locks taken by by pid %08lx", refcnt, pid );
  2019. } /* RemoveProcessLocks */