Skip to content

Commit

Permalink
Better handling of multiple null rect locks
Browse files Browse the repository at this point in the history
  • Loading branch information
elishacloud committed Mar 23, 2024
1 parent 7ae07bd commit eb0d44f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Dllmain/BuildNo.rc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#define BUILD_NUMBER 6976
#define BUILD_NUMBER 6977
6 changes: 6 additions & 0 deletions ddraw/IDirect3DDeviceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,12 @@ HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpSur
{
lpDDSrcSurfaceX = nullptr;

if (!CheckSurfaceExists(lpSurface))
{
LOG_LIMIT(100, __FUNCTION__ << " Error: could not find source surface! " << lpSurface);
return DDERR_INVALIDPARAMS;
}

lpSurface->QueryInterface(IID_GetInterfaceX, (LPVOID*)&lpDDSrcSurfaceX);

if (!lpDDSrcSurfaceX)
Expand Down
48 changes: 38 additions & 10 deletions ddraw/IDirectDrawSurfaceX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2345,12 +2345,27 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur
HRESULT ret = LockD39Surface(&LockedRect, &DestRect, Flags);
if (FAILED(ret))
{
if (IsSurfaceLocked())
// If surface is locked already with null rect
if (IsSurfaceLocked() && LockRectList.empty())
{
LOG_LIMIT(100, __FUNCTION__ << " Warning: attempting to lock surface twice!");
if (!LastLock.LockedRect.pBits || !LastLock.LockedRect.Pitch)
{
LOG_LIMIT(100, __FUNCTION__ << " Error: could not get last lock data!");
}
LockedRect.pBits = LastLock.LockedRect.pBits;
LockedRect.Pitch = LastLock.LockedRect.Pitch;
ret = DD_OK;
}
// If surface is locked with specific rect
else
{
if (IsSurfaceLocked())
{
LOG_LIMIT(100, __FUNCTION__ << " Warning: attempting to lock surface twice!");
}
UnlockD39Surface();
ret = LockD39Surface(&LockedRect, &DestRect, Flags);
}
UnlockD39Surface();
ret = LockD39Surface(&LockedRect, &DestRect, Flags);
}
if (FAILED(ret))
{
Expand Down Expand Up @@ -2379,6 +2394,7 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur
// Set lock flag
IsLocked = true;

// Set thread ID
if (LockedWithID)
{
LOG_LIMIT(100, __FUNCTION__ << " Warning: surface locked thread ID set! " << LockedWithID);
Expand All @@ -2391,6 +2407,10 @@ HRESULT m_IDirectDrawSurfaceX::Lock2(LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSur
RECT lRect = { lpDestRect->left, lpDestRect->top, lpDestRect->right, lpDestRect->bottom };
LockRectList.push_back(lRect);
}
else
{
LockedCount++;
}

// Set surfaceDesc
if (!(lpDDSurfaceDesc2->dwFlags & DDSD_LPSURFACE))
Expand Down Expand Up @@ -2819,12 +2839,6 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect)
{
SetSurfaceCriticalSection();

// Emulate unlock
if (EmuLock.Locked)
{
UnlockEmuLock();
}

HRESULT hr = DD_OK;

do {
Expand Down Expand Up @@ -2862,6 +2876,14 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect)
}
}

// Check if locked more than once with null rect
if (LockedCount > 1)
{
LockedCount--;
hr = DD_OK;
break;
}

// Check for device interface
HRESULT c_hr = CheckInterface(__FUNCTION__, true, true, true);
if (FAILED(c_hr))
Expand All @@ -2870,6 +2892,12 @@ HRESULT m_IDirectDrawSurfaceX::Unlock(LPRECT lpRect)
break;
}

// Emulate unlock
if (EmuLock.Locked)
{
UnlockEmuLock();
}

// Remove scanlines before unlocking surface
if (Config.DdrawRemoveScanlines && IsPrimaryOrBackBuffer())
{
Expand Down
5 changes: 3 additions & 2 deletions ddraw/IDirectDrawSurfaceX.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
DWORD MaxLOD = 0;

bool Is3DRenderingTarget = false; // Surface used for Direct3D rendering target, called from m_IDirect3DX::CreateDevice()
bool Using3D = false; // Direct3D is being used on top of DirectDraw
bool Using3D = false; // Direct3D is being used on top of DirectDraw
bool DCRequiresEmulation = false;
bool SurfaceRequiresEmulation = false;
bool ComplexRoot = false;
Expand All @@ -136,7 +136,8 @@ class m_IDirectDrawSurfaceX : public IUnknown, public AddressLookupTableDdrawObj
bool IsInBlt = false;
bool IsInBltBatch = false;
bool IsLocked = false;
DWORD LockedWithID = 0;
DWORD LockedCount = 0; // Counts the number of null rect locks happen
DWORD LockedWithID = 0; // Thread ID of the current lock
LASTLOCK LastLock; // Remember the last lock info
std::vector<RECT> LockRectList; // Rects used to lock the surface
DDRAWEMULATELOCK EmuLock; // For aligning bits after a lock for games that hard code the pitch
Expand Down

0 comments on commit eb0d44f

Please sign in to comment.