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

/*==========================================================================
*
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
*
* File: ddsacc.c
* Content: Direct Draw surface access support
* Lock & Unlock
* History:
* Date By Reason
* ==== == ======
* 10-jan-94 craige initial implementation
* 13-jan-95 craige re-worked to updated spec + ongoing work
* 22-jan-95 craige made 32-bit + ongoing work
* 31-jan-95 craige and even more ongoing work...
* 04-feb-95 craige performance tuning, ongoing work
* 27-feb-95 craige new sync. macros
* 02-mar-95 craige use pitch (not stride)
* 15-mar-95 craige HEL
* 19-mar-95 craige use HRESULTs
* 20-mar-95 craige validate locking rectangle
* 01-apr-95 craige happy fun joy updated header file
* 07-apr-95 craige bug 2 - unlock should accept the screen ptr
* take/release Win16Lock when access GDI's surface
* 09-apr-95 craige maintain owner of Win16Lock so we can release it
* if someone forgets; remove locks from dead processes
* 12-apr-95 craige don't use GETCURRPID; fixed Win16 lock deadlock
* condition
* 06-may-95 craige use driver-level csects only
* 12-jun-95 craige new process list stuff
* 18-jun-95 craige allow duplicate surfaces
* 25-jun-95 craige one ddraw mutex; hold DDRAW lock when locking primary
* 26-jun-95 craige reorganized surface structure
* 28-jun-95 craige ENTER_DDRAW at very start of fns
* 03-jul-95 craige YEEHAW: new driver struct; SEH
* 07-jul-95 craige added test for BUSY
* 08-jul-95 craige take Win16 lock always on surface lock
* 09-jul-95 craige win16 lock re-entrant, so count it!
* 11-jul-95 craige set busy bit when taking win16 lock to avoid GDI from
* drawing on the display.
* 13-jul-95 craige ENTER_DDRAW is now the win16 lock
* 16-jul-95 craige check DDRAWISURF_HELCB
* 31-jul-95 craige don't return error from HAL unlock if not handled;
* validate flags
* 01-aug-95 craig use bts for setting & testing BUSY bit
* 04-aug-95 craige added InternalLock/Unlock
* 10-aug-95 toddla added DDLOCK_WAIT flag
* 12-aug-95 craige bug 488: need to call tryDoneLock even after HAL call
* to Unlock
* 18-aug-95 toddla DDLOCK_READONLY and DDLOCK_WRITEONLY
* 27-aug-95 craige bug 723 - treat vram & sysmem the same when locking
* 09-dec-95 colinmc Added execute buffer support
* 11-dec-95 colinmc Added lightweight(-ish) Lock and Unlock for use by
* Direct3D (exported as private DLL API).
* 02-jan-96 kylej handle new interface structs.
* 26-jan-96 jeffno Lock/Unlock no longer special-case whole surface...
* You need to record what ptr was given to user since
* it will not be same as kernel-mode ptr
* 01-feb-96 colinmc Fixed nasty bug causing Win16 lock to be released
* on surfaces explicitly created in system memory
* which did not take the lock in the first place
* 12-feb-96 colinmc Surface lost flag moved from global to local object
* 13-mar-96 jeffno Do not allow lock on an NT emulated primary!
* 18-apr-96 kylej Bug 18546: Take bytes per pixel into account when
* calculating lock offset.
* 20-apr-96 kylej Bug 15268: exclude the cursor when a primary
* surface rect is locked.
* 01-may-96 colinmc Bug 20005: InternalLock does not check for lost
* surfaces
* 17-may-96 mdm Bug 21499: perf problems with new InternalLock
* 14-jun-96 kylej NT Bug 38227: Added DDLOCK_FAILONVISRGNCHANGED so
* that InternalLock() can fail if the vis rgn is not
* current. This flag is only used on NT.
* 05-jul-96 colinmc Work Item: Remove requirement on taking Win16 lock
* for VRAM surfaces (not primary)
* 10-oct-96 colinmc Refinements of the Win16 locking stuff
* 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
* memory usage
* 01-feb-97 colinmc Bug 5457: Fixed Win16 lock problem causing hang
* with mutliple AMovie instances on old cards
* 11-mar-97 jeffno Asynchronous DMA support
* 23-mar-97 colinmc Hold Win16 lock for AGP surfaces for now
* 24-mar-97 jeffno Optimized Surfaces
* 03-oct-97 jeffno DDSCAPS2 and DDSURFACEDESC2
* 19-dec-97 jvanaken IDDS4::Unlock now takes pointer to rectangle.
*
***************************************************************************/
#include "ddrawpr.h"
#ifdef WINNT
#include "ddrawgdi.h"
#endif
/*
* Bit number of the VRAM flag in the PDEVICE dwFlags field.
*/
#define VRAM_BIT 15
/* doneBusyWin16Lock releases the win16 lock and busy bit. It is used
* in lock routines for failure cases in which we have not yet
* incremented the win16 lock or taken the DD critical section a
* second time. It is also called by tryDoneLock. */
static void doneBusyWin16Lock( LPDDRAWI_DIRECTDRAW_GBL pdrv )
{
#ifdef WIN95
if( pdrv->dwWin16LockCnt == 0 )
{
*(pdrv->lpwPDeviceFlags) &= ~BUSY;
}
#ifdef WIN16_SEPARATE
LEAVE_WIN16LOCK();
#endif
#endif
} /* doneBusyWin16Lock */
/* tryDoneLock releases the win16 lock and busy bit. It is used in
* unlock routines since it decrements the Win16 count in addition to
* releasing the lock. WARNING: This function does nothing and
* returns no error if the win16 lock is not owned by the current DD
* object. This will result in the lock being held and will probably
* bring the machine to its knees. */
static void tryDoneLock( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, DWORD pid )
{
LPDDRAWI_DIRECTDRAW_GBL pdrv = pdrv_lcl->lpGbl;
if( pdrv->dwWin16LockCnt == 0 )
{
return;
}
pdrv->dwWin16LockCnt--;
doneBusyWin16Lock( pdrv );
LEAVE_DDRAW();
} /* tryDoneLock */
#ifdef USE_ALIAS
/*
* Undo an aliased lock.
*
* An aliased lock is one which required the PDEVICE VRAM bit
* to be cleared to prevent the accelerator touching memory
* at the same time as the locked surface.
*
* NOTE: The lock does not necessarily have to be on a VRAM
* surface. Locks of implicit system memory surfaces also
* clear the VRAM bit (to ensure similar behaviour for
* system and video memory surfaces).
*/
static void undoAliasedLock( LPDDRAWI_DIRECTDRAW_GBL pdrv )
{
DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
#ifdef WIN16_SEPARATE
ENTER_WIN16LOCK();
#endif
pdrv->dwAliasedLockCnt--;
if( 0UL == pdrv->dwAliasedLockCnt )
{
/*
* That was the last outstanding aliased lock on this
* device so put the VRAM bit in the PDEVICE back the
* way it was.
*/
if( pdrv->dwFlags & DDRAWI_PDEVICEVRAMBITCLEARED )
{
/*
* The VRAM bit was set when we took the first lock so
* we had to clear it. We must now set it again.
*/
DPF( 4, "PDevice was VRAM - restoring VRAM bit", pdrv );
*(pdrv->lpwPDeviceFlags) |= VRAM;
pdrv->dwFlags &= ~DDRAWI_PDEVICEVRAMBITCLEARED;
}
}
#ifdef WIN16_SEPARATE
LEAVE_WIN16LOCK();
#endif
}
#endif /* USE_ALIAS */
#ifdef WIN95
#define DONE_LOCK_EXCLUDE() \
if( this_lcl->dwFlags & DDRAWISURF_LOCKEXCLUDEDCURSOR ) \
{ \
DD16_Unexclude(pdrv->dwPDevice); \
this_lcl->dwFlags &= ~DDRAWISURF_LOCKEXCLUDEDCURSOR; \
}
#else
#define DONE_LOCK_EXCLUDE() ;
#endif
/*
* The following two routines are used by D3D on NT to manipulate
* the DDraw mutex exclusion mechanism
*/
void WINAPI AcquireDDThreadLock(void)
{
ENTER_DDRAW();
}
void WINAPI ReleaseDDThreadLock(void)
{
LEAVE_DDRAW();
}
HRESULT WINAPI DDInternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID* lpBits )
{
return InternalLock(this_lcl, lpBits, NULL, DDLOCK_TAKE_WIN16_VRAM |
DDLOCK_FAILLOSTSURFACES);
}
HRESULT WINAPI DDInternalUnlock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl )
{
BUMP_SURFACE_STAMP(this_lcl->lpGbl);
return InternalUnlock(this_lcl, NULL, NULL, DDLOCK_TAKE_WIN16_VRAM);
}
#define DPF_MODNAME "InternalLock"
#if !defined( WIN16_SEPARATE) || defined(WINNT)
#pragma message(REMIND("InternalLock not tested without WIN16_SEPARATE."))
#endif // WIN16_SEPARATE
/*
* InternalLock provides the basics of locking for trusted clients.
* No parameter validation is done and no ddsd is filled in. The
* client promises the surface is not lost and is otherwise well
* constructed. If caller does not pass DDLOCK_TAKE_WIN16 in dwFlags,
* we assume the DDraw critical section, Win16 lock, and busy bit are
* already entered/set. If caller does pass DDLOCK_TAKE_WIN16,
* InternalLock will do so if needed. Note that passing
* DDLOCK_TAKE_WIN16 does not necessarily result in the Win16 lock
* being taken. It is only taken if needed.
*/
HRESULT InternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID *pbits,
LPRECT lpDestRect, DWORD dwFlags )
{
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdrv;
DWORD this_lcl_caps;
LPDDRAWI_DDRAWSURFACE_GBL this;
DWORD rc;
DDHAL_LOCKDATA ld;
LPDDHALSURFCB_LOCK lhalfn;
LPDDHALSURFCB_LOCK lfn;
BOOL emulation;
LPACCESSRECTLIST parl;
LPWORD pdflags = NULL;
BOOL isvramlock = FALSE;
#ifdef USE_ALIAS
BOOL holdwin16lock;
#endif /* USE_ALIAS */
FLATPTR OldfpVidMem; //Used to detect if driver moved surface on Lock call
this = this_lcl->lpGbl;
this_lcl_caps = this_lcl->ddsCaps.dwCaps;
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
pdrv = pdrv_lcl->lpGbl;
#ifdef WINNT
// Update DDraw handle in driver GBL object.
pdrv->hDD = pdrv_lcl->hDD;
#endif
ENTER_DDRAW();
/*
* If the surface was involved in a hardware op, we need to
* probe the driver to see if it's done. NOTE this assumes
* that only one driver can be responsible for a system memory
* operation.
* This operation is done at the API level Lock since the situation we
* need to avoid is the CPU and the DMA/Busmaster hitting a surface
* at the same time. We can trust the HAL driver to know it should not
* try to DMA out of the same surface twice. This is almost certainly
* enforced anyway by the likelihood that the hardware will have only
* one context with which to perform the transfer: it has to wait.
*/
if( this->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED )
{
WaitForDriverToFinishWithSurface(this_lcl->lpSurfMore->lpDD_lcl, this_lcl);
}
// The following code was added to keep all of the HALs from
// changing their Lock() code when they add video port support.
// If the video port was using this surface but was recently
// flipped, we will make sure that the flip actually occurred
// before allowing access. This allows double buffered capture
// w/o tearing.
// ScottM 7/10/96
if( this_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT )
{
LPDDRAWI_DDVIDEOPORT_INT lpVideoPort;
LPDDRAWI_DDVIDEOPORT_LCL lpVideoPort_lcl;
// Look at all video ports to see if any of them recently
// flipped from this surface.
lpVideoPort = pdrv->dvpList;
while( NULL != lpVideoPort )
{
lpVideoPort_lcl = lpVideoPort->lpLcl;
if( lpVideoPort_lcl->fpLastFlip == this->fpVidMem )
{
// This can potentially tear - check the flip status
LPDDHALVPORTCB_GETFLIPSTATUS pfn;
DDHAL_GETVPORTFLIPSTATUSDATA GetFlipData;
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
pfn = pdrv_lcl->lpDDCB->HALDDVideoPort.GetVideoPortFlipStatus;
if( pfn != NULL ) // Will simply tear if function not supproted
{
GetFlipData.lpDD = pdrv_lcl;
GetFlipData.fpSurface = this->fpVidMem;
KeepTrying:
rc = DDHAL_DRIVER_NOTHANDLED;
DOHALCALL( GetVideoPortFlipStatus, pfn, GetFlipData, rc, 0 );
if( ( DDHAL_DRIVER_HANDLED == rc ) &&
( DDERR_WASSTILLDRAWING == GetFlipData.ddRVal ) )
{
if( dwFlags & DDLOCK_WAIT)
{
goto KeepTrying;
}
LEAVE_DDRAW();
return DDERR_WASSTILLDRAWING;
}
}
}
lpVideoPort = lpVideoPort->lpLink;
}
}
// Check for VRAM access - if yes, we need to take the win16 lock
// and the busy bit. From the user API, we treat the vram and
// implicit sysmemory cases the same because many developers were
// treating them differently and then breaking when they actually
// got vram. Also, we only bother with this if the busy bit (and
// Win16 lock) are currently available.
/*
* NOTE: The semantics are that for each VRAM (or simulated VRAM lock)
* the Win16 lock and BUSY bit are held until we have called the
* driver and are sure we can do an aliased lock (in which case we
* release them). Otherwise, we keep holding them.
*
* IMPORTANT NOTE: Behaviour change. Previously we did not perform
* the Win16 locking actions if this was not the first lock of this
* surface. This no longer works as we can no longer ensure all the
* necessary locking actions will happen on the first lock of the
* surface. For example, the first lock on the surface may be
* aliasable so we don't set the busy bit. A subsequent lock may
* not be aliasable, however, so we need to take the lock on that
* occassion. This should not, however, be much of a hit as the
* really expensive actions only take place on the first
* Win16 lock (0UL == pdrv->dwWin16LockCnt) so once someone has
* taken the Win16 lock remaining locks should be cheap. Also,
* multiple locks are unusual so, all in all, this should be pretty
* low risk.
*/
FlushD3DStates(this_lcl);
#if COLLECTSTATS
if(this_lcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
++this_lcl->lpSurfMore->lpDD_lcl->dwNumTexLocks;
#endif
if( ( ((dwFlags & DDLOCK_TAKE_WIN16) && !(this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED)) ||
((dwFlags & DDLOCK_TAKE_WIN16_VRAM) && (this_lcl_caps & DDSCAPS_VIDEOMEMORY)) )
&& (pdrv->dwFlags & DDRAWI_DISPLAYDRV) )
{
DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
!(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
DPF( 5, "Performing VRAM style lock for surface 0x%08x", this_lcl );
/*
* Lock of a VRAM surface (or a surface being treated like a VRAM surface)
* with no outstanding locks pending. Take the Win16 lock.
*/
isvramlock = TRUE;
#ifdef WIN95
// Don't worry about the busy bit for NT
/*
* We always take the Win16 lock while we mess with the driver's
* busy bits. However, if we have a surface with an alias we
* will release the Win16 lock before we exit this function.
*/
#ifdef WIN16_SEPARATE
ENTER_WIN16LOCK();
#endif // WIN16_SEPARATE
// If dwWin16LockCnt > 0 then we already set the busy bit, so
// don't bother doing it again. NOTE: this assumption may be
// limiting.
if( 0UL == pdrv->dwWin16LockCnt )
{
BOOL isbusy;
pdflags = pdrv->lpwPDeviceFlags;
isbusy = 0;
_asm
{
mov eax, pdflags
bts word ptr [eax], BUSY_BIT
adc isbusy,0
}
if( isbusy )
{
DPF( 2, "BUSY - Lock, dwWin16LockCnt = %ld, %04x, %04x (%ld)",
pdrv->dwWin16LockCnt, *pdflags, BUSY, BUSY_BIT );
#ifdef WIN16_SEPARATE
LEAVE_WIN16LOCK();
#endif // WIN16_SEPARATE
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
} // isbusy
} // ( 0UL == pdrv->dwWin16LockCnt )
#endif // WIN95
} // VRAM locking actions (Win16 lock, busy bit).
// If we have been asked to check for lost surfaces do it NOW after
// the Win16 locking code. This is essential as otherwise we may
// lose the surface after the check but before we actually get round
// to doing anything with the surface
if( ( dwFlags & DDLOCK_FAILLOSTSURFACES ) && SURFACE_LOST( this_lcl ) )
{
DPF_ERR( "Surface is lost - can't lock" );
#if defined( WIN16_SEPARATE) && !defined(WINNT)
if( isvramlock )
doneBusyWin16Lock( pdrv );
#endif
LEAVE_DDRAW();
return DDERR_SURFACELOST;
}
// Make sure someone else has not already locked the part of the
// surface we want. We don't need to worry about this for DX8
// resource management. In fact, for vertex buffers, the following
// code doesn't work because the Rect is actually a linear range.
if(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
!(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
{
BOOL hit = FALSE;
if( lpDestRect != NULL )
{
// Caller has asked to lock a subsection of the surface.
parl = this->lpRectList;
// Run through all rectangles, looking for an intersection.
while( parl != NULL )
{
RECT res;
if( IntersectRect( &res, lpDestRect, &parl->rDest ) )
{
hit = TRUE;
break;
}
parl = parl->lpLink;
}
}
// Either (our rect overlaps with someone else's rect), or
// (someone else has locked the entire surface), or
// (someone locked part of the surface but we want to lock the whole thing).
if( hit ||
(this->lpRectList == NULL && this->dwUsageCount > 0) ||
((lpDestRect == NULL) && ((this->dwUsageCount > 0) || (this->lpRectList != NULL))) )
{
DPF(2,"Surface is busy: parl=0x%x, lpDestRect=0x%x, "
"this->dwUsageCount=0x%x, this->lpRectList=0x%x, hit=%d",
parl,lpDestRect,this->dwUsageCount,this->lpRectList,hit );
#if defined( WIN16_SEPARATE) && !defined(WINNT)
if( isvramlock )
{
doneBusyWin16Lock( pdrv );
}
#endif
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
// Create a rectangle access list member. Note that for
// performance, we don't do this on 95 if the user is locking
// the whole surface.
parl = NULL;
if(lpDestRect)
{
parl = MemAlloc( sizeof( ACCESSRECTLIST ) );
if( parl == NULL )
{
#if defined( WIN16_SEPARATE) && !defined(WINNT)
if( isvramlock )
{
doneBusyWin16Lock( pdrv );
}
#endif
DPF(0,"InternalLock: Out of memory.");
LEAVE_DDRAW();
return DDERR_OUTOFMEMORY;
}
if(lpDestRect != NULL)
{
parl->lpLink = this->lpRectList;
parl->rDest = *lpDestRect;
}
else
{
parl->lpLink = NULL;
parl->rDest.top = 0;
parl->rDest.left = 0;
parl->rDest.bottom = (int) (DWORD) this->wHeight;
parl->rDest.right = (int) (DWORD) this->wWidth;
}
parl->lpOwner = pdrv_lcl;
#ifdef USE_ALIAS
parl->dwFlags = 0UL;
parl->lpHeapAliasInfo = NULL;
#endif /* USE_ALIAS */
this->lpRectList = parl;
//parl->lpSurfaceData is filled below, after HAL call
/*
* Add a rect to the region list if this is a managed surface and not a read only lock
*/
if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
{
LPREGIONLIST lpRegionList = this_lcl->lpSurfMore->lpRegionList;
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
lpRegionList->rect[(lpRegionList->rdh.nCount)++] = *((LPRECTL)lpDestRect);
lpRegionList->rdh.nRgnSize += sizeof(RECT);
if((lpDestRect->left & 0xffff) < lpRegionList->rdh.rcBound.left)
lpRegionList->rdh.rcBound.left = lpDestRect->left & 0xffff;
if((lpDestRect->right & 0xfff)> lpRegionList->rdh.rcBound.right)
lpRegionList->rdh.rcBound.right = lpDestRect->right & 0xffff;
if(lpDestRect->top < lpRegionList->rdh.rcBound.top)
lpRegionList->rdh.rcBound.top = lpDestRect->top;
if(lpDestRect->bottom > lpRegionList->rdh.rcBound.bottom)
lpRegionList->rdh.rcBound.bottom = lpDestRect->bottom;
}
}
}
else
{
/*
* We are locking the whole surface, so by setting nCount to the
* max number of dirty rects allowed, we will force the cache
* manager to update the entire surface
*/
if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
{
this_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
}
}
}
else
{
parl = NULL;
DDASSERT(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8);
DDASSERT(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE);
}
// Increment the usage count of this surface.
this->dwUsageCount++;
CHANGE_GLOBAL_CNT( pdrv, this, 1 );
// Is this an emulation surface or driver surface?
//
// NOTE: There are different HAL entry points for execute buffers
// and conventional surfaces.
if( (this_lcl_caps & DDSCAPS_SYSTEMMEMORY) ||
(this_lcl->dwFlags & DDRAWISURF_HELCB) )
{
if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
lfn = pdrv_lcl->lpDDCB->HELDDExeBuf.LockExecuteBuffer;
else
lfn = pdrv_lcl->lpDDCB->HELDDSurface.Lock;
lhalfn = lfn;
emulation = TRUE;
}
else
{
if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
{
lfn = pdrv_lcl->lpDDCB->HALDDExeBuf.LockExecuteBuffer;
lhalfn = pdrv_lcl->lpDDCB->cbDDExeBufCallbacks.LockExecuteBuffer;
}
else
{
lfn = pdrv_lcl->lpDDCB->HALDDSurface.Lock;
lhalfn = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Lock;
}
emulation = FALSE;
}
#ifdef WIN95
/*
* exclude the mouse cursor if this is the display driver
* and we are locking a rect on the primary surface.
* and the driver is not using a HW cursor
*/
if ( (pdrv->dwFlags & DDRAWI_DISPLAYDRV) && pdrv->dwPDevice &&
(this_lcl_caps & DDSCAPS_PRIMARYSURFACE) && lpDestRect &&
!(*pdrv->lpwPDeviceFlags & HARDWARECURSOR))
{
DD16_Exclude(pdrv->dwPDevice, (RECTL *)lpDestRect);
this_lcl->dwFlags |= DDRAWISURF_LOCKEXCLUDEDCURSOR;
}
#endif
//Remember the old fpVidMem in case the driver changes is
OldfpVidMem = this->fpVidMem;
// See if the driver wants to say something...
rc = DDHAL_DRIVER_NOTHANDLED;
if( lhalfn != NULL )
{
DPF(4,"InternalLock: Calling driver Lock.");
ld.Lock = lhalfn;
ld.lpDD = pdrv;
ld.lpDDSurface = this_lcl;
#ifdef WIN95
ld.dwFlags = dwFlags;
#else
#pragma message(REMIND("So far the s3 driver will only succeed if flags==0"))
ld.dwFlags = dwFlags & (DDLOCK_NOOVERWRITE | DDLOCK_READONLY | DDLOCK_WRITEONLY | DDLOCK_NOSYSLOCK | DDLOCK_DISCARDCONTENTS);
#endif
if( lpDestRect != NULL )
{
ld.bHasRect = TRUE;
ld.rArea = *(LPRECTL)lpDestRect;
}
else
{
ld.bHasRect = FALSE;
}
try_again:
#ifdef WINNT
do
{
if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
{
DOHALCALL( LockExecuteBuffer, lfn, ld, rc, emulation );
}
else
{
DOHALCALL( Lock, lfn, ld, rc, emulation );
if ( (dwFlags & DDLOCK_FAILONVISRGNCHANGED) ||
!(rc == DDHAL_DRIVER_HANDLED && ld.ddRVal == DDERR_VISRGNCHANGED) )
break;
DPF(4,"Resetting VisRgn for surface %x", this_lcl);
DdResetVisrgn(this_lcl, (HWND)0);
}
}
while (rc == DDHAL_DRIVER_HANDLED && ld.ddRVal == DDERR_VISRGNCHANGED);
#else
if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
{
DOHALCALL( LockExecuteBuffer, lfn, ld, rc, emulation );
}
else
{
DOHALCALL( Lock, lfn, ld, rc, emulation );
}
#endif
}
if( rc == DDHAL_DRIVER_HANDLED )
{
if( ld.ddRVal == DD_OK )
{
DPF(5,"lpsurfdata is %08x",ld.lpSurfData);
#ifdef WINNT
if ( (ld.lpSurfData == (void*) ULongToPtr(0xffbadbad)) && (dwFlags & DDLOCK_FAILEMULATEDNTPRIMARY) )
{
ld.ddRVal = DDERR_CANTLOCKSURFACE;
}
#endif
*pbits = ld.lpSurfData;
}
else if( (dwFlags & DDLOCK_WAIT) && ld.ddRVal == DDERR_WASSTILLDRAWING )
{
DPF(4, "Waiting...");
goto try_again;
}
if (ld.ddRVal != DD_OK)
{
// Failed!
#ifdef DEBUG
if( (ld.ddRVal != DDERR_WASSTILLDRAWING) && (ld.ddRVal != DDERR_SURFACELOST) )
{
DPF( 0, "Driver failed Lock request: %ld", ld.ddRVal );
}
#endif
// Unlink the rect list item.
if(parl)
{
this->lpRectList = parl->lpLink;
MemFree( parl );
}
// Now unlock the surface and bail.
this->dwUsageCount--;
CHANGE_GLOBAL_CNT( pdrv, this, -1 );
#if defined( WIN16_SEPARATE) && !defined(WINNT)
if( isvramlock )
{
doneBusyWin16Lock( pdrv );
}
#endif
DONE_LOCK_EXCLUDE();
LEAVE_DDRAW();
return ld.ddRVal;
} // ld.ddRVal
}
else // DDHAL_DRIVER_HANDLED
{
#ifdef WINNT
// If the driver fails the lock, we can't allow the app to scribble with
// who knows what fpVidMem...
*pbits = (LPVOID) ULongToPtr(0x80000000); // Illegal for user-mode, as is anything higher.
DPF_ERR("Driver did not handle Lock call. App may Access Violate");
// Unlink the rect list item.
if( parl )
{
this->lpRectList = parl->lpLink;
MemFree( parl );
}
// Now unlock the surface and bail.
this->dwUsageCount--;
CHANGE_GLOBAL_CNT( pdrv, this, -1 );
DONE_LOCK_EXCLUDE();
LEAVE_DDRAW();
return DDERR_SURFACEBUSY; //GEE: Strange error to use, but most appropriate
#else // WIN95
DPF(4,"Driver did not handle Lock call. Figure something out.");
// Get a pointer to the surface bits.
if( this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE )
{
*pbits = (LPVOID) pdrv->vmiData.fpPrimary;
}
else
{
*pbits = (LPVOID) this->fpVidMem;
}
if( ld.bHasRect)
{
DWORD bpp;
DWORD byte_offset;
DWORD left = (DWORD) ld.rArea.left;
// Make the surface pointer point to the first byte of the requested rectangle.
if( ld.lpDDSurface->dwFlags & DDRAWISURF_HASPIXELFORMAT )
{
bpp = ld.lpDDSurface->lpGbl->ddpfSurface.dwRGBBitCount;
}
else
{
bpp = ld.lpDD->vmiData.ddpfDisplay.dwRGBBitCount;
}
if (ld.lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
{
left &= 0xffff;
}
switch(bpp)
{
case 1: byte_offset = left>>3; break;
case 2: byte_offset = left>>2; break;
case 4: byte_offset = left>>1; break;
case 8: byte_offset = left; break;
case 16: byte_offset = left*2; break;
case 24: byte_offset = left *3; break;
case 32: byte_offset = left *4; break;
}
*pbits = (LPVOID) ((DWORD)*pbits +
(DWORD)ld.rArea.top * ld.lpDDSurface->lpGbl->lPitch +
byte_offset);
if (ld.lpDDSurface->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
{
((BYTE*)*pbits) += (ld.rArea.left >> 16) * ld.lpDDSurface->lpGbl->lSlicePitch;
}
}
#endif // WIN95
} // !DDHAL_DRIVER_HANDLED
if(!(dwFlags & DDLOCK_READONLY) && IsD3DManaged(this_lcl))
MarkDirty(this_lcl);
// Filled in, as promised above.
if(parl)
{
parl->lpSurfaceData = *pbits;
}
//
// At this point we are committed to the lock.
//
// stay holding the lock if needed
if( isvramlock )
{
#ifdef USE_ALIAS
LPHEAPALIASINFO pheapaliasinfo;
pheapaliasinfo = NULL;
holdwin16lock = TRUE;
#ifdef DEBUG
/*
* Force or disable the Win16 locking behaviour
* dependent on the registry settings.
*/
if( dwRegFlags & DDRAW_REGFLAGS_DISABLENOSYSLOCK )
dwFlags &= ~DDLOCK_NOSYSLOCK;
if( dwRegFlags & DDRAW_REGFLAGS_FORCENOSYSLOCK )
dwFlags |= DDLOCK_NOSYSLOCK;
#endif /* DEBUG */
#endif
DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
!(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
if( dwFlags & DDLOCK_NOSYSLOCK )
{
#ifdef WINNT
if( NULL != parl )
parl->dwFlags |= ACCESSRECT_NOTHOLDINGWIN16LOCK;
else
this->dwGlobalFlags |= DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK;
LEAVE_DDRAW();
}
else
#endif /* WINNT */
#ifdef USE_ALIAS
/*
* Remember that this was a VRAM style lock (need this when cleaning
* up).
*/
if( NULL != parl )
parl->dwFlags |= ACCESSRECT_VRAMSTYLE;
else
this->dwGlobalFlags |= DDRAWISURFGBL_LOCKVRAMSTYLE;
/*
* At this point we have a pointer to the non-aliased video memory which was
* either returned to us by the driver or which we computed ourselves. In
* either case, if this is a video memory style lock on a surface that is
* aliasable and the pointer computed lies in the range of one our aliased
* video memory heaps we wish to use that pointer instead of the real video
* memory pointer.
*/
if( ( this_lcl_caps & DDSCAPS_PRIMARYSURFACE ) )
{
/*
* If we have a primary surface we need to hold the Win16 lock even
* though we have aliases. This is to prevent USER
* from coming in and changing clip lists or drawing all over our locked
* data.
*/
DPF( 2, "Surface is primary. Holding the Win16 lock" );
}
else
{
if( pdrv->dwFlags & DDRAWI_NEEDSWIN16FORVRAMLOCK )
{
/*
* For some reason this device needs the Win16 lock for VRAM surface
* locking. This is probably because its bankswitched or we have a
* DIB engine we don't understand.
*/
DPF( 2, "Device needs to hold Win16 lock for VRAM surface locks" );
}
else
{
if( NULL == pdrv->phaiHeapAliases )
{
/*
* We don't have any heaps aliases but we are not a device which
* needs the Win16 lock. This means we must be an emulation or
* ModeX device. In which case we don't need to hold the Win16
* lock for the duration.
*/
DDASSERT( ( pdrv->dwFlags & DDRAWI_NOHARDWARE ) || ( pdrv->dwFlags & DDRAWI_MODEX ) );
DPF( 2, "Emulation or ModeX device. No need to hold Win16 lock" );
holdwin16lock = FALSE;
}
else
{
if( this_lcl_caps & DDSCAPS_SYSTEMMEMORY )
{
/*
* If the surface is an implicit system memory surface then we
* take aliased style actions but we don't actually compute an alias.
*/
holdwin16lock = FALSE;
}
else
{
FLATPTR paliasbits;
LPDDRAWI_DDRAWSURFACE_GBL_MORE lpGblMore;
DDASSERT( this_lcl_caps & DDSCAPS_VIDEOMEMORY );
lpGblMore = GET_LPDDRAWSURFACE_GBL_MORE( this );
// We use the cached alias if available and valid. We determine validity by comparing
// *pbits with the original fpVidMem that was used to compute the alias. If they match
// then it is safe to use the pointer.
// The reason we need to do this is that the driver can change the fpVidMem of the surface.
// This change can occur during any Lock calls or (in case of D3D Vertex / Command buffers)
// outside of lock (during DrawPrimitives2 DDI call). Thus we need to make sure the surface
// is pointing to the same memory as it was when we computed the alias. (anujg 8/13/99)
if( ( 0UL != lpGblMore->fpAliasedVidMem ) &&
( lpGblMore->fpAliasOfVidMem == (FLATPTR) *pbits ) )
{
DPF( 4, "Lock vidmem pointer matches stored vidmem pointer - using cached alias" );
paliasbits = lpGblMore->fpAliasedVidMem;
}
else
{
DPF( 4, "Lock vidmem pointer does not match vidmem pointer - recomputing" );
paliasbits = GetAliasedVidMem( pdrv_lcl, this_lcl, (FLATPTR) *pbits );
// Store this value for future use...
if (this->fpVidMem == (FLATPTR)*pbits)
{
lpGblMore->fpAliasedVidMem = paliasbits;
lpGblMore->fpAliasOfVidMem = this->fpVidMem;
}
}
if( 0UL != paliasbits )
{
DPF( 5, "Got aliased pointer = 0x%08x", paliasbits );
*pbits = (LPVOID) paliasbits;
if( NULL != parl )
parl->lpSurfaceData = *pbits;
holdwin16lock = FALSE;
pheapaliasinfo = pdrv->phaiHeapAliases;
}
}
/*
* If we have got this far for an execute buffer, it means that we have a
* pointer to system memory even though the DDSCAPS_SYSTEMMEMORY is not
* set. Thus it is ok to not hold the win16 lock, etc.
* Basically what this amounts to is that we never take the win16 lock
* for execute buffers. We first try and see if we can find an alias
* to the pointer, and if we can't we assume it is in system memory and
* not take the win16 lock in any case. (anujg 4/7/98)
*/
if( this_lcl_caps & DDSCAPS_EXECUTEBUFFER )
{
holdwin16lock = FALSE;
}
}
}
}
}
if( !holdwin16lock )
{
/*
* We have an aliased lock so we don't need to hold onto the Win16
* and busy bit. However, we do need to clear the VRAM bit in the
* PDEVICE (if we have not done this already). We also need to
* patch the DIB engine to correct the some of the problems we
* have in turning the VRAM bit off. Once that is done we can
* release the Win16 lock and BUSY bit.
*
* NOTE: We only need do this if there are no outstanding aliased
* locks off this device
*
* NOTE #2: We also do not need to do this for aliased locks to
* execute buffers as this is just trying to prevent DIB Engine
* from using HW accelleration when there is an outstanding aliased lock
* This is not necessary for the new HW which will be implementing EB
* in video memory
*/
if( 0UL == pdrv->dwAliasedLockCnt && !(this_lcl_caps & DDSCAPS_EXECUTEBUFFER))
{
BOOL vrambitset;
pdflags = pdrv->lpwPDeviceFlags;
/*
* Clear the PDEVICE's VRAM bit and return its previous status
* in vrambit
*/
vrambitset = 0;
_asm
{
mov eax, pdflags
btr word ptr [eax], VRAM_BIT
adc vrambitset,0
}
/*
* We use a global device object flag to remember the original
* state of the VRAM flag.
*/
if( vrambitset )
{
/*
* The VRAM bit in the PDEVICE was set. Need to record the fact
* that it was cleared by a lock (so we can put the correct
* state back).
*/
DPF( 4, "VRAM bit was cleared for lock of surface 0x%08x", this_lcl );
pdrv->dwFlags |= DDRAWI_PDEVICEVRAMBITCLEARED;
}
#ifdef DEBUG
else
{
/*
* NOTE: This can happen if we are running emulated.
*/
DPF( 4, "VRAM bit was already clear on lock of surface 0x%08x", this_lcl );
DDASSERT( !( pdrv->dwFlags & DDRAWI_PDEVICEVRAMBITCLEARED ) );
}
#endif
}
/*
* Bump the count on the number of outstanding aliased locks.
*/
pdrv->dwAliasedLockCnt++;
if(!(this_lcl_caps & DDSCAPS_EXECUTEBUFFER))
{
// This is used to check if the graphics adapter is busy for Blts, Flips, etc
// instead of dwAliasedLockCnt. This enables Blts & Flips when we have an
// outstanding aliased lock to an exceute buffer since this will be common
// in D3D. We increment this is all other cases to preserve original behavior.
if( ( pdrv->lpDDKernelCaps == NULL ) ||
!( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
{
pdrv->dwBusyDueToAliasedLock++;
}
}
/*
* If we are a real video memory surface then we need to hold a
* reference to the heap aliases so they don't go away before we
* unlock.
*/
if( NULL != pheapaliasinfo )
{
DDASSERT( this_lcl_caps & DDSCAPS_VIDEOMEMORY );
DDASSERT( pheapaliasinfo->dwFlags & HEAPALIASINFO_MAPPEDREAL );
pheapaliasinfo->dwRefCnt++;
}
/*
* Remember that this lock is using an alias and not holding the Win16 lock.
*/
if( NULL != parl )
{
parl->lpHeapAliasInfo = pheapaliasinfo;
parl->dwFlags |= ACCESSRECT_NOTHOLDINGWIN16LOCK;
}
else
{
this_lcl->lpSurfMore->lpHeapAliasInfo = pheapaliasinfo;
this->dwGlobalFlags |= DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK;
}
/*
* All has gone well so there is no need to hold the Win16 lock and busy
* bit. Release them now.
*/
doneBusyWin16Lock( pdrv );
/*
* We do not hold the DirectDraw critical section across the lock
* either.
*/
LEAVE_DDRAW();
DPF( 5, "Win16 lock not held for lock of surface 0x%08x", this_lcl );
}
else
#endif /* USE_ALIAS */
{
/*
* We don't LEAVE_DDRAW() to avoid race conditions (someone
* could ENTER_DDRAW() and then wait on the Win16 lock but we
* can't release it because we can't get in the critical
* section).
* Even though we don't take the Win16 lock under NT, we
* continue to hold the DirectDraw critical section as
* long as a vram surface is locked.
*/
pdrv->dwWin16LockCnt++;
DPF( 5, "Win16 lock was held for lock of surface 0x%08x", this_lcl );
}
}
else
{
LEAVE_DDRAW();
}
return DD_OK;
} /* InternalLock */
/*
* InternalUnlock
*/
HRESULT InternalUnlock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID lpSurfaceData,
LPRECT lpDestRect, DWORD dwFlags )
{
LPDDRAWI_DDRAWSURFACE_GBL this;
DWORD rc;
DDHAL_UNLOCKDATA uld;
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdrv;
LPDDHALSURFCB_UNLOCK ulhalfn;
LPDDHALSURFCB_UNLOCK ulfn;
BOOL emulation;
LPACCESSRECTLIST parl;
DWORD caps;
BOOL holdingwin16;
#ifdef USE_ALIAS
LPHEAPALIASINFO pheapaliasinfo;
BOOL lockbroken = FALSE;
#endif /* USE_ALIAS */
DDASSERT(lpSurfaceData == NULL || lpDestRect == NULL);
this = this_lcl->lpGbl;
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
pdrv = pdrv_lcl->lpGbl;
caps = this_lcl->ddsCaps.dwCaps;
if( this->dwUsageCount == 0 )
{
DPF_ERR( "ERROR: Surface not locked." );
return DDERR_NOTLOCKED;
}
ENTER_DDRAW();
/* under NT we cannot compare the locked ptr with fpPrimary since
* a user-mode address may not necesarily match a kernel-mode
* address. Now we allocate an ACCESSRECTLIST structure on every
* lock, and store the user's vidmem ptr in that. The user's
* vidmem ptr cannot change between a lock and an unlock because
* the surface will be locked during that time (!) (even tho the
* physical ram that's mapped at that address might change... that
* win16lock avoidance thing). This is a very very small
* performance hit over doing it the old way. ah well. jeffno
* 960122 */
if( NULL != this->lpRectList )
{
DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
!(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
/*
* One or more locks are active on this surface.
*/
if( NULL != lpDestRect || NULL != lpSurfaceData )
{
LPACCESSRECTLIST last;
BOOL found;
found = FALSE;
/*
* The locked region of the surface is specified by either a
* dest rect or a surface pointer (but never both). Find the
* specified region in our list of locked regions on this surface.
*/
last = NULL;
parl = this->lpRectList;
if( NULL != lpDestRect )
{
/*
* Locked region of surface is specified by dest rect.
*/
while( parl != NULL )
{
if( !memcmp(&parl->rDest, lpDestRect, sizeof(RECT)) )
{
found = TRUE;
break;
}
last = parl;
parl = parl->lpLink;
}
}
else
{
/*
* Locked region of surface is specified by surface ptr.
*/
while( parl != NULL )
{
if( parl->lpSurfaceData == lpSurfaceData )
{
found = TRUE;
break;
}
last = parl;
parl = parl->lpLink;
}
}
/*
* did we find a match?
*/
if( !found )
{
DPF_ERR( "Specified rectangle is not a locked area" );
LEAVE_DDRAW();
return DDERR_NOTLOCKED;
}
/*
* make sure unlocking process is the one who locked it
*/
if( pdrv_lcl != parl->lpOwner )
{
DPF_ERR( "Current process did not lock this rectangle" );
LEAVE_DDRAW();
return DDERR_NOTLOCKED;
}
/*
* delete this rect
*/
if( last == NULL )
{
this->lpRectList = parl->lpLink;
}
else
{
last->lpLink = parl->lpLink;
}
}
else
{
// Both lpDestRect and lpSurfaceData are null, so there better be
// only one lock on the surface - the whole thing. Make sure that
// if no rectangle was specified that there's only one entry in the
// access list - the one that was made during lock.
parl = this->lpRectList;
if( parl->lpLink == NULL )
{
DPF(5,"--Unlock: parl->rDest really set to (L=%d,T=%d,R=%d,B=%d)",
parl->rDest.left, parl->rDest.top, parl->rDest.right, parl->rDest.bottom);
/*
* make sure unlocking process is the one who locked it
*/
if( pdrv_lcl != parl->lpOwner )
{
DPF_ERR( "Current process did not lock this rectangle" );
LEAVE_DDRAW();
return DDERR_NOTLOCKED; //what's a better error than this?
}
this->lpRectList = NULL;
}
else
{
DPF_ERR( "Multiple locks on surface -- you must specify a rectangle" );
LEAVE_DDRAW();
return DDERR_INVALIDRECT;
}
}
DDASSERT( NULL != parl );
if( parl->dwFlags & ACCESSRECT_NOTHOLDINGWIN16LOCK )
{
holdingwin16 = FALSE;
#ifdef USE_ALIAS
/*
* This flag should only be set for VRAM style locks.
*/
DDASSERT( parl->dwFlags & ACCESSRECT_VRAMSTYLE );
pheapaliasinfo = parl->lpHeapAliasInfo;
#endif /* USE_ALIAS */
}
else
{
holdingwin16 = TRUE;
}
#ifdef USE_ALIAS
if( parl->dwFlags & ACCESSRECT_BROKEN )
lockbroken = TRUE;
#endif /* USE_ALIAS */
MemFree( parl );
}
else
{
/*
* Lock of the entire surface (no access rect). Determine whether
* this lock held the Win16 lock by using global surface object
* flags (as we have no access rect).
*/
if( this->dwGlobalFlags & DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK )
{
holdingwin16 = FALSE;
#ifdef USE_ALIAS
/*
* This flag should only get set for VRAM style locks.
*/
DDASSERT( this->dwGlobalFlags & DDRAWISURFGBL_LOCKVRAMSTYLE );
pheapaliasinfo = this_lcl->lpSurfMore->lpHeapAliasInfo;
this_lcl->lpSurfMore->lpHeapAliasInfo = NULL;
#endif /* USE_ALIAS */
}
else
{
holdingwin16 = TRUE;
}
#ifdef USE_ALIAS
if( this->dwGlobalFlags & DDRAWISURFGBL_LOCKBROKEN )
lockbroken = TRUE;
#endif /* USE_ALIAS */
this->dwGlobalFlags &= ~( DDRAWISURFGBL_LOCKVRAMSTYLE |
DDRAWISURFGBL_LOCKBROKEN |
DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK );
}
#ifdef WINNT
if (this->dwGlobalFlags & DDRAWISURFGBL_NOTIFYWHENUNLOCKED)
{
if (--dwNumLockedWhenModeSwitched == 0)
{
NotifyDriverOfFreeAliasedLocks();
}
this->dwGlobalFlags &= ~DDRAWISURFGBL_NOTIFYWHENUNLOCKED;
}
#endif
/*
* remove one of the users...
*/
this->dwUsageCount--;
CHANGE_GLOBAL_CNT( pdrv, this, -1 );
#ifdef USE_ALIAS
/*
* The semantics I have choosen for surfaces which are locked when they
* get themselves invalidates is to make the application call unlock the
* appropriate number of times (this for our housekeeping and also for
* back compatability with existing applications which don't expect to
* lose locked surfaces and so we be set up to call lock regardless.
* However, in the case of surfaces that are released when locked we
* break the locks but don't call the unlock method in the driver we
* mirror that here. If a lock has been broken we don't call the HAL.
*/
if( !lockbroken )
{
#endif /* USE_ALIAS */
/*
* Is this an emulation surface or driver surface?
*
* NOTE: Different HAL entry points for execute
* buffers.
*/
if( (caps & DDSCAPS_SYSTEMMEMORY) ||
(this_lcl->dwFlags & DDRAWISURF_HELCB) )
{
if( caps & DDSCAPS_EXECUTEBUFFER )
ulfn = pdrv_lcl->lpDDCB->HELDDExeBuf.UnlockExecuteBuffer;
else
ulfn = pdrv_lcl->lpDDCB->HELDDSurface.Unlock;
ulhalfn = ulfn;
emulation = TRUE;
}
else
{
if( caps & DDSCAPS_EXECUTEBUFFER )
{
ulfn = pdrv_lcl->lpDDCB->HALDDExeBuf.UnlockExecuteBuffer;
ulhalfn = pdrv_lcl->lpDDCB->cbDDExeBufCallbacks.UnlockExecuteBuffer;
}
else
{
ulfn = pdrv_lcl->lpDDCB->HALDDSurface.Unlock;
ulhalfn = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.Unlock;
}
emulation = FALSE;
}
/*
* Let the driver know about the unlock.
*/
uld.ddRVal = DD_OK;
if( ulhalfn != NULL )
{
uld.Unlock = ulhalfn;
uld.lpDD = pdrv;
uld.lpDDSurface = this_lcl;
if( caps & DDSCAPS_EXECUTEBUFFER )
{
DOHALCALL( UnlockExecuteBuffer, ulfn, uld, rc, emulation );
}
else
{
DOHALCALL( Unlock, ulfn, uld, rc, emulation );
}
if( rc != DDHAL_DRIVER_HANDLED )
{
uld.ddRVal = DD_OK;
}
}
#ifdef USE_ALIAS
}
else
{
DPF( 4, "Lock broken - not calling HAL on Unlock" );
uld.ddRVal = DD_OK;
}
#endif /* USE_ALIAS */
/* Release the win16 lock but only if the corresponding lock took
* the win16 lock which in the case of the API level lock and
* unlock calls is if the user requests it and the surface was not
* explicitly allocated in system memory.
*
* IMPORTANT NOTE: Again we no longer only do this for the first lock
* on a surface. This matches the code path for lock.
*/
if( ( ((dwFlags & DDLOCK_TAKE_WIN16) && !(this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED)) ||
((dwFlags & DDLOCK_TAKE_WIN16_VRAM) && (caps & DDSCAPS_VIDEOMEMORY)) )
&& (pdrv->dwFlags & DDRAWI_DISPLAYDRV) )
{
DDASSERT(!(this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8) ||
!(this_lcl->lpSurfMore->ddsCapsEx.dwCaps2 & DDSCAPS2_TEXTUREMANAGE));
if( !holdingwin16 )
{
#ifdef USE_ALIAS
/*
* Cleanup the PDEVICE's VRAM bit (if this is the last outstanding
* VRAM lock.
*/
undoAliasedLock( pdrv );
if(!(caps & DDSCAPS_EXECUTEBUFFER))
{
// This is used to check if the graphics adapter is busy for Blts, Flips, etc
// instead of dwAliasedLockCnt. Make sure we decrement it for everything but
// execute buffers.
if( ( pdrv->lpDDKernelCaps == NULL ) ||
!( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
{
pdrv->dwBusyDueToAliasedLock--;
}
}
/*
* We don't need the aliases anymore.
*
* NOTE: We don't actually have to have an alias. If this is
* a VRAM style lock of an implicit system memory surface then
* no alias is actually used.
*/
if( NULL != pheapaliasinfo )
{
DDASSERT( 0UL != pdrv_lcl->hDDVxd );
ReleaseHeapAliases( (HANDLE) pdrv_lcl->hDDVxd, pheapaliasinfo );
}
#endif /* USE_ALIAS */
}
else
{
tryDoneLock( pdrv_lcl, 0 );
}
/*
* If it was a vram lock then we did not release the DirectDraw critical
* section on the lock. We need to release it now.
*/
}
// Unexclude the cursor if it was excluded in Lock.
DONE_LOCK_EXCLUDE();
LEAVE_DDRAW();
return uld.ddRVal;
} /* InternalUnlock */
#undef DPF_MODNAME
#define DPF_MODNAME "Lock"
/*
* DD_Surface_Lock
*
* Allows access to a surface.
*
* A pointer to the video memory is returned. The primary surface
* can change from call to call, if page flipping is turned on.
*/
//#define ALLOW_COPY_ON_LOCK
#ifdef ALLOW_COPY_ON_LOCK
HDC hdcPrimaryCopy=0;
HBITMAP hbmPrimaryCopy=0;
#endif
HRESULT DDAPI DD_Surface_Lock(
LPDIRECTDRAWSURFACE lpDDSurface,
LPRECT lpDestRect,
LPDDSURFACEDESC lpDDSurfaceDesc,
DWORD dwFlags,
HANDLE hEvent )
{
LPDDRAWI_DDRAWSURFACE_INT this_int;
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
LPDDRAWI_DDRAWSURFACE_GBL this;
DWORD this_lcl_caps;
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdrv;
HRESULT ddrval;
LPVOID pbits;
BOOL fastlock;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_Surface_Lock %p", ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSurface)->lpLcl);
if (lpDestRect != NULL)
DPF(2,A,"Lock rectangle (%d, %d, %d, %d)", lpDestRect->left, lpDestRect->top, lpDestRect->right, lpDestRect->bottom);
/* DPF_ENTERAPI(lpDDSurface); */
/*
* Problem: Under NT, there is no cross-process pointer to any given video-memory surface.
* So how do you tell if an lpVidMem you passed back to the user is the same as the fpPrimaryOrig that
* was previously stored in the ddraw gbl struct? You can't. Previously, we did a special case lock
* when the user requested the whole surface (lpDestRect==NULL). Now we allocate a ACCESSRECTLIST
* structure on every lock, and if lpDestRect==NULL, we put the top-left vidmemptr into that structure.
* Notice we can guarantee that this ptr will be valid at unlock time because the surface remains
* locked for all that time (obviously!).
* This is a minor minor minor perf hit, but what the hey.
* jeffno 960122
*/
TRY
{
/*
* validate parms
*/
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSurface;
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
{
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
this_lcl_caps = this_lcl->ddsCaps.dwCaps;
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
pdrv = pdrv_lcl->lpGbl;
if( SURFACE_LOST( this_lcl ) )
{
LEAVE_DDRAW();
return DDERR_SURFACELOST;
}
fastlock = (this_lcl->lpSurfMore->lpDD_lcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW7) &&
(NULL == pdrv_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus ||
!(this->dwGlobalFlags & DDRAWISURFGBL_HARDWAREOPSTARTED)) &&
!(this_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT) &&
(this->dwGlobalFlags & DDRAWISURFGBL_SYSMEMREQUESTED) &&
(this_lcl_caps & DDSCAPS_TEXTURE);
#ifndef DEBUG
if(!fastlock)
#endif
{
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
{
DPF_ERR( "It is an optimized surface" );
LEAVE_DDRAW();
return DDERR_ISOPTIMIZEDSURFACE;
}
if( dwFlags & ~DDLOCK_VALID )
{
DPF_ERR( "Invalid flags" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if (!LOWERTHANSURFACE7(this_int))
{
if (dwFlags & DDLOCK_DONOTWAIT)
{
dwFlags &= ~DDLOCK_WAIT;
}
else
{
dwFlags |= DDLOCK_WAIT;
}
}
if( !VALID_DDSURFACEDESC_PTR( lpDDSurfaceDesc ) &&
!VALID_DDSURFACEDESC2_PTR( lpDDSurfaceDesc ) )
{
DPF_ERR( "Invalid surface description ptr" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
lpDDSurfaceDesc->lpSurface = NULL;
/*
* Make sure the process locking this surface is the one
* that created it.
*/
if( this_lcl->dwProcessId != GetCurrentProcessId() )
{
DPF_ERR( "Current process did not create this surface" );
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
/* Check out the rectangle, if any.
*
* NOTE: We don't allow the specification of a rectangle with an
* execute buffer.
*/
if( lpDestRect != NULL )
{
if( !VALID_RECT_PTR( lpDestRect ) || ( this_lcl_caps & DDSCAPS_EXECUTEBUFFER ) )
{
DPF_ERR( "Invalid destination rectangle pointer" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
} // valid pointer
/*
* make sure rectangle is OK
*/
if( (lpDestRect->left < 0) ||
(lpDestRect->top < 0) ||
(lpDestRect->left > lpDestRect->right) ||
(lpDestRect->top > lpDestRect->bottom) ||
(lpDestRect->bottom > (int) (DWORD) this->wHeight) ||
(lpDestRect->right > (int) (DWORD) this->wWidth) )
{
DPF_ERR( "Invalid rectangle given" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
} // checking rectangle
}
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if(fastlock)
{
DPF(4, "Performing fast lock");
lpDDSurfaceDesc->lpSurface = NULL;
#ifdef DEBUG
if(this->fpVidMem != (FLATPTR)NULL)
{
if(this->fpVidMem != (FLATPTR)0xFFBADBAD)
#endif
{
if(this->dwUsageCount == 0)
{
FlushD3DStates(this_lcl);
#if COLLECTSTATS
if(this_lcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
++this_lcl->lpSurfMore->lpDD_lcl->dwNumTexLocks;
#endif
if( lpDestRect != NULL )
{
DWORD byte_offset;
/*
* Add a rect to the region list if this is a managed surface and not a read only lock
*/
if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
{
LPREGIONLIST lpRegionList = this_lcl->lpSurfMore->lpRegionList;
if(lpRegionList->rdh.nCount != NUM_RECTS_IN_REGIONLIST)
{
lpRegionList->rect[(lpRegionList->rdh.nCount)++] = *((LPRECTL)lpDestRect);
lpRegionList->rdh.nRgnSize += sizeof(RECT);
if(lpDestRect->left < lpRegionList->rdh.rcBound.left)
lpRegionList->rdh.rcBound.left = lpDestRect->left;
if(lpDestRect->right > lpRegionList->rdh.rcBound.right)
lpRegionList->rdh.rcBound.right = lpDestRect->right;
if(lpDestRect->top < lpRegionList->rdh.rcBound.top)
lpRegionList->rdh.rcBound.top = lpDestRect->top;
if(lpDestRect->bottom > lpRegionList->rdh.rcBound.bottom)
lpRegionList->rdh.rcBound.bottom = lpDestRect->bottom;
}
MarkDirty(this_lcl);
}
// Make the surface pointer point to the first byte of the requested rectangle.
switch((this_lcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) ? this->ddpfSurface.dwRGBBitCount : pdrv->vmiData.ddpfDisplay.dwRGBBitCount)
{
case 1: byte_offset = ((DWORD)lpDestRect->left)>>3; break;
case 2: byte_offset = ((DWORD)lpDestRect->left)>>2; break;
case 4: byte_offset = ((DWORD)lpDestRect->left)>>1; break;
case 8: byte_offset = (DWORD)lpDestRect->left; break;
case 16: byte_offset = (DWORD)lpDestRect->left*2; break;
case 24: byte_offset = (DWORD)lpDestRect->left*3; break;
case 32: byte_offset = (DWORD)lpDestRect->left*4; break;
}
pbits = (LPVOID) ((ULONG_PTR)this->fpVidMem + (DWORD)lpDestRect->top * this->lPitch + byte_offset);
}
else
{
/*
* We are locking the whole surface, so by setting nCount to the
* max number of dirty rects allowed, we will force the cache
* manager to update the entire surface
*/
if(IsD3DManaged(this_lcl) && !(dwFlags & DDLOCK_READONLY))
{
this_lcl->lpSurfMore->lpRegionList->rdh.nCount = NUM_RECTS_IN_REGIONLIST;
MarkDirty(this_lcl);
}
pbits = (LPVOID) this->fpVidMem;
}
// Increment the usage count of this surface.
this->dwUsageCount++;
// Reset hardware op status
this->dwGlobalFlags &= ~DDRAWISURFGBL_HARDWAREOPSTARTED;
// Free cached RLE data
if( GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved )
{
MemFree( (void *)(GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved) );
GET_LPDDRAWSURFACE_GBL_MORE(this)->dwHELReserved = 0;
}
this->dwGlobalFlags |= DDRAWISURFGBL_FASTLOCKHELD;
ddrval = DD_OK;
}
else
{
DPF_ERR("Surface already locked");
ddrval = DDERR_SURFACEBUSY;
}
}
#ifdef DEBUG
else
{
this->dwGlobalFlags |= DDRAWISURFGBL_FASTLOCKHELD;
ddrval = DD_OK;
}
}
else
{
ddrval = DDERR_GENERIC;
}
#endif
}
else
{
// Params are okay, so call InternalLock() to do the work.
ddrval = InternalLock(this_lcl, &pbits, lpDestRect, dwFlags | DDLOCK_TAKE_WIN16 | DDLOCK_FAILEMULATEDNTPRIMARY);
}
if(ddrval != DD_OK)
{
if( (ddrval != DDERR_WASSTILLDRAWING) && (ddrval != DDERR_SURFACELOST) )//both useless as spew
{
DPF_ERR("InternalLock failed.");
}
LEAVE_DDRAW();
return ddrval;
}
if (dwFlags & DDLOCK_READONLY)
this->dwGlobalFlags |= DDRAWISURFGBL_READONLYLOCKHELD;
else
this->dwGlobalFlags &= ~DDRAWISURFGBL_READONLYLOCKHELD;
FillEitherDDSurfaceDesc( this_lcl, (LPDDSURFACEDESC2) lpDDSurfaceDesc );
lpDDSurfaceDesc->lpSurface = pbits;
DPF_STRUCT(3,A,DDSURFACEDESC,lpDDSurfaceDesc);
LEAVE_DDRAW();
return DD_OK;
} /* DD_Surface_Lock */
#undef DPF_MODNAME
#define DPF_MODNAME "Unlock"
/*
* Perform the parameter checking and surface unlocking for the
* IDirectDrawSurface::Unlock API call. This function is called
* from both the DD_Surface_Unlock and DD_Surface_Unlock4 entry
* points. Argument lpSurfaceData is always NULL when the call
* is from DD_SurfaceUnlock4, and argument lpDestRect is always
* NULL when the call is from DD_Surface_Unlock.
*/
HRESULT unlockMain(
LPDIRECTDRAWSURFACE lpDDSurface,
LPVOID lpSurfaceData,
LPRECT lpDestRect )
{
LPDDRAWI_DDRAWSURFACE_INT this_int;
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
LPDDRAWI_DDRAWSURFACE_GBL this;
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdrv;
LPACCESSRECTLIST parl;
HRESULT err;
/*
* validate parameters
*/
TRY
{
this_int = (LPDDRAWI_DDRAWSURFACE_INT) lpDDSurface;
if( !VALID_DIRECTDRAWSURFACE_PTR( this_int ) )
{
return DDERR_INVALIDOBJECT;
}
this_lcl = this_int->lpLcl;
this = this_lcl->lpGbl;
pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
pdrv = pdrv_lcl->lpGbl;
#ifndef DEBUG
if(!(this->dwGlobalFlags & DDRAWISURFGBL_FASTLOCKHELD))
#endif
{
//
// For now, if the current surface is optimized, quit
//
if (this_lcl->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
{
DPF_ERR( "It is an optimized surface" );
return DDERR_ISOPTIMIZEDSURFACE;
}
if (lpDestRect != NULL)
{
/*
* Make sure the specified rectangle pointer is valid.
*/
if (!VALID_RECT_PTR(lpDestRect))
{
DPF_ERR( "Invalid destination rectangle pointer" );
return DDERR_INVALIDPARAMS;
}
}
/*
* make sure process accessed this surface
*/
if( this_lcl->dwProcessId != GetCurrentProcessId() )
{
DPF_ERR( "Current process did not lock this surface" );
return DDERR_NOTLOCKED;
}
/*
* was surface accessed?
*/
if( this->dwUsageCount == 0 )
{
return DDERR_NOTLOCKED;
}
/*
* if the usage count is bigger than one, then you had better tell
* me what region of the screen you were using...
*/
if( this->dwUsageCount > 1 && lpSurfaceData == NULL && lpDestRect == NULL)
{
return DDERR_INVALIDRECT;
}
/*
* We don't want apps to hold a DC when the surface is not locked,
* but failing right now could cause regression issues, so we will
* output a banner when we see this an fail on the new interfaces.
*/
if( ( this_lcl->dwFlags & DDRAWISURF_HASDC ) &&
!( this_lcl->ddsCaps.dwCaps & DDSCAPS_OWNDC ) )
{
DPF_ERR( "***************************************************" );
DPF_ERR( "** Application called Unlock w/o releasing the DC!!" );
DPF_ERR( "***************************************************" );
if( ( this_int->lpVtbl != &ddSurfaceCallbacks ) &&
( this_int->lpVtbl != &ddSurface2Callbacks ) )
{
return DDERR_GENERIC;
}
}
/*
* if no rect list, no one has locked
*/
parl = this->lpRectList;
}
}
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
{
DPF_ERR( "Exception encountered validating parameters" );
return DDERR_INVALIDPARAMS;
}
if(this->dwGlobalFlags & DDRAWISURFGBL_FASTLOCKHELD)
{
DPF(4, "Performing fast unlock");
--this->dwUsageCount;
DDASSERT(this->dwUsageCount == 0);
err = DD_OK;
this->dwGlobalFlags &= ~DDRAWISURFGBL_FASTLOCKHELD;
}
else
{
err = InternalUnlock(this_lcl,lpSurfaceData,lpDestRect,DDLOCK_TAKE_WIN16);
}
//We only bump the surface stamp if the lock was NOT read only
if ( (this->dwGlobalFlags & DDRAWISURFGBL_READONLYLOCKHELD) == 0)
{
DPF(4,"Bumping surface stamp");
BUMP_SURFACE_STAMP(this);
}
this->dwGlobalFlags &= ~DDRAWISURFGBL_READONLYLOCKHELD;
#ifdef WINNT
if( SURFACE_LOST( this_lcl ) )
{
err = DDERR_SURFACELOST;
}
#endif
return err;
} /* unlockMain */
/*
* DD_Surface_Unlock
*
* Done accessing a surface. This is the version used for interfaces
* IDirectDrawSurface, IDirectDrawSurface2, and IDirectDrawSurface3.
*/
HRESULT DDAPI DD_Surface_Unlock(
LPDIRECTDRAWSURFACE lpDDSurface,
LPVOID lpSurfaceData )
{
LPDDRAWI_DDRAWSURFACE_INT this_int;
LPDDRAWI_DDRAWSURFACE_LCL this_lcl;
LPDDRAWI_DDRAWSURFACE_GBL this;
HRESULT ddrval;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_Surface_Unlock %p", lpDDSurface);
ddrval = unlockMain(lpDDSurface, lpSurfaceData, NULL);
LEAVE_DDRAW();
return (ddrval);
} /* DD_Surface_Unlock */
/*
* DD_Surface_Unlock4
*
* Done accessing a surface. This is the version used for interfaces
* IDirectDrawSurface4 and higher.
*/
HRESULT DDAPI DD_Surface_Unlock4(
LPDIRECTDRAWSURFACE lpDDSurface,
LPRECT lpDestRect )
{
HRESULT ddrval;
RECT rDest;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_Surface_Unlock4");
ddrval = unlockMain(lpDDSurface, NULL, lpDestRect);
LEAVE_DDRAW();
return (ddrval);
} /* DD_Surface_Unlock4 */
#ifdef USE_ALIAS
/*
* BreakSurfaceLocks
*
* Mark any locks held by a surface as broken. This is called when
* invalidating a surface (due to a mode switch). The semantics are
* that a surface destroy is an implict unlock on all locks on the
* surface. Thus, we don't call the HAL unlock, only the HAL destroy.
*/
void BreakSurfaceLocks( LPDDRAWI_DDRAWSURFACE_GBL this )
{
LPACCESSRECTLIST lpRect;
DPF( 4, "Breaking locks on the surface 0x%08x", this );
if( 0UL != this->dwUsageCount )
{
if( NULL != this->lpRectList )
{
for( lpRect = this->lpRectList; NULL != lpRect; lpRect = lpRect->lpLink )
lpRect->dwFlags |= ACCESSRECT_BROKEN;
}
else
{
DDASSERT( 1UL == this->dwUsageCount );
this->dwGlobalFlags |= DDRAWISURFGBL_LOCKBROKEN;
}
}
} /* BreakSurfaceLocks */
#endif /* USE_ALIAS */
/*
* RemoveProcessLocks
*
* Remove all Lock calls made a by process on a surface.
* assumes driver lock is taken
*/
void RemoveProcessLocks(
LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl,
LPDDRAWI_DDRAWSURFACE_LCL this_lcl,
DWORD pid )
{
LPDDRAWI_DIRECTDRAW_GBL pdrv=pdrv_lcl->lpGbl;
LPDDRAWI_DDRAWSURFACE_GBL this=this_lcl->lpGbl;
DWORD refcnt;
LPACCESSRECTLIST parl;
LPACCESSRECTLIST last;
LPACCESSRECTLIST next;
/*
* remove all rectangles we have accessed
*/
refcnt = (DWORD) this->dwUsageCount;
if( refcnt == 0 )
{
return;
}
parl = this->lpRectList;
last = NULL;
while( parl != NULL )
{
next = parl->lpLink;
if( parl->lpOwner == pdrv_lcl )
{
DPF( 5, "Cleaning up lock to rectangle (%ld,%ld),(%ld,%ld) by pid %08lx",
parl->rDest.left,parl->rDest.top,
parl->rDest.right,parl->rDest.bottom,
pid );
refcnt--;
this->dwUsageCount--;
CHANGE_GLOBAL_CNT( pdrv, this, -1 );
#ifdef USE_ALIAS
/*
* If this was a vram style lock and it didn't hold the Win16 lock
* then we need to decrement the number of aliased locks held.
*/
if( ( parl->dwFlags & ACCESSRECT_VRAMSTYLE ) &&
( parl->dwFlags & ACCESSRECT_NOTHOLDINGWIN16LOCK ) )
{
DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
undoAliasedLock( pdrv );
if(!(this_lcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
// This is used to check if the graphics adapter is busy for Blts, Flips, etc
// instead of dwAliasedLockCnt. Make sure we decrement it for everything but
// execute buffers.
if( ( pdrv->lpDDKernelCaps == NULL ) ||
!( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
{
pdrv->dwBusyDueToAliasedLock--;
}
}
/*
* If we are holding a referenced to an aliased heap release it
* now.
*/
if( NULL != parl->lpHeapAliasInfo )
ReleaseHeapAliases( GETDDVXDHANDLE( pdrv_lcl ) , parl->lpHeapAliasInfo );
}
#endif /* USE_ALIAS */
if( last == NULL )
{
this->lpRectList = next;
}
else
{
last->lpLink = next;
}
MemFree( parl );
}
else
{
last = parl;
}
parl = next;
}
#ifdef USE_ALIAS
/*
* Was the entire surface locked with a video memory style
* lock (but without the Win16 lock held)? If so then we
* again need to decrement the aliased lock count.
*/
if( ( this->dwGlobalFlags & DDRAWISURFGBL_LOCKVRAMSTYLE ) &&
( this->dwGlobalFlags & DDRAWISURFGBL_LOCKNOTHOLDINGWIN16LOCK ) )
{
DDASSERT( 0UL != pdrv->dwAliasedLockCnt );
undoAliasedLock( pdrv );
if(!(this_lcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
// This is used to check if the graphics adapter is busy for Blts, Flips, etc
// instead of dwAliasedLockCnt. Make sure we decrement it for everything but
// execute buffers.
if( ( pdrv->lpDDKernelCaps == NULL ) ||
!( pdrv->lpDDKernelCaps->dwCaps & DDKERNELCAPS_LOCK ) )
{
pdrv->dwBusyDueToAliasedLock--;
}
}
/*
* If we are holding a referenced to an aliased heap release it
* now.
*/
if( NULL != this_lcl->lpSurfMore->lpHeapAliasInfo )
{
ReleaseHeapAliases( GETDDVXDHANDLE( pdrv_lcl ), this_lcl->lpSurfMore->lpHeapAliasInfo );
this_lcl->lpSurfMore->lpHeapAliasInfo = NULL;
}
}
#endif /* USE_ALIAS */
/*
* remove the last of the refcnts we have
*/
this->dwUsageCount -= (short) refcnt;
CHANGE_GLOBAL_CNT( pdrv, this, -1*refcnt );
/*
* clean up the win16 lock
*
* NOTE: This is not surface related this just breaks the Win16
* lock and device busy bits held by the device. You realy only
* want to do this once not once per surface.
*/
/*
* blow away extra locks if the the process is still alive
*/
if( pid == GetCurrentProcessId() )
{
DPF( 5, "Cleaning up %ld Win16 locks", pdrv->dwWin16LockCnt );
while( pdrv->dwWin16LockCnt > 0 )
{
tryDoneLock( pdrv_lcl, pid );
}
}
else
{
/*
* !!! NOTE: Does not reset the BUSY bit!
*/
DPF( 4, "Process dead, resetting Win16 lock cnt" );
pdrv->dwWin16LockCnt = 0;
}
DPF( 5, "Cleaned up %ld locks taken by by pid %08lx", refcnt, pid );
} /* RemoveProcessLocks */